Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 2 | |
Furquan Shaikh | 76cedd2 | 2020-05-02 10:24:23 -0700 | [diff] [blame] | 3 | #include <acpi/acpi_device.h> |
Aaron Durbin | 77a062e | 2020-08-20 10:15:06 -0600 | [diff] [blame] | 4 | #include <acpi/acpigen.h> |
Tim Wawrzynczak | 84428f7 | 2021-09-14 13:59:33 -0600 | [diff] [blame] | 5 | #include <boot/coreboot_tables.h> |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 6 | #include <device/pci.h> |
| 7 | #include <device/pci_ids.h> |
Nikolai Vyssotski | 95675d9 | 2021-02-09 13:01:07 -0600 | [diff] [blame] | 8 | #include <console/console.h> |
| 9 | #include <fsp/graphics.h> |
Nikolai Vyssotski | ad68e69 | 2021-01-15 11:39:33 -0600 | [diff] [blame] | 10 | #include <soc/intel/common/vbt.h> |
Nikolai Vyssotski | b649d6a | 2021-03-11 19:15:03 -0600 | [diff] [blame] | 11 | #include <timestamp.h> |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 12 | |
Aaron Durbin | 77a062e | 2020-08-20 10:15:06 -0600 | [diff] [blame] | 13 | #define ATIF_FUNCTION_VERIFY_INTERFACE 0x0 |
| 14 | struct atif_verify_interface_output { |
| 15 | uint16_t size; /* Size of this object, including size field */ |
| 16 | uint16_t version; |
| 17 | uint32_t supported_notifications; |
| 18 | uint32_t supported_functions; /* Bit n set if function n+1 supported. */ |
| 19 | }; |
| 20 | |
| 21 | #define ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS 0x10 |
| 22 | # define ATIF_QBTC_REQUEST_LCD1 0 |
| 23 | /* error codes */ |
| 24 | # define ATIF_QBTC_ERROR_CODE_SUCCESS 0 |
| 25 | # define ATIF_QBTC_ERROR_CODE_FAILURE 1 |
| 26 | # define ATIF_QBTC_ERROR_CODE_DEVICE_NOT_SUPPORTED 2 |
| 27 | struct atif_brightness_input { |
| 28 | uint16_t size; |
| 29 | /* ATIF doc indicates this field is a word, but the kernel drivers uses a byte. */ |
| 30 | uint8_t requested_display; |
| 31 | }; |
| 32 | struct atif_brightness_output { |
| 33 | uint16_t size; /* Size of this object, including size field. */ |
| 34 | uint16_t flags; /* Currently all reserved. */ |
| 35 | uint8_t error_code; |
| 36 | /* default brightness fields currently ignored by Linux driver. */ |
| 37 | uint8_t default_brightness_ac; /* Percentage brightness when connected to AC. */ |
| 38 | uint8_t default_brightness_dc; /* Percentage brightness when connected to DC. */ |
| 39 | /* The following 2 fields are the only ones honored by Linux driver currently. */ |
| 40 | uint8_t min_input_signal_level; /* 0-255 corresponding to 0% */ |
| 41 | uint8_t max_input_signal_level; /* 0-255 corresponding to 100% */ |
| 42 | /* Array of data points consisting of: |
| 43 | * { uint8_t luminance_level; (percent) |
| 44 | * uint8_t input_signal_level; (0-255 in value) } |
| 45 | * Linux ignores these fields so no support currently. */ |
| 46 | uint8_t count_data_points; /* Count of data points. */ |
| 47 | }; |
| 48 | |
| 49 | static void generate_atif(const struct device *dev) |
| 50 | { |
| 51 | struct atif_verify_interface_output verify_output = { |
| 52 | .size = sizeof(verify_output), |
| 53 | .version = 1, |
| 54 | .supported_functions = |
| 55 | BIT(ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS - 1), |
| 56 | }; |
| 57 | struct atif_brightness_output brightness_error = { |
| 58 | .size = sizeof(brightness_error), |
| 59 | .error_code = ATIF_QBTC_ERROR_CODE_DEVICE_NOT_SUPPORTED, |
| 60 | }; |
| 61 | struct atif_brightness_output brightness_out = { |
| 62 | .size = sizeof(brightness_out), |
| 63 | .error_code = ATIF_QBTC_ERROR_CODE_SUCCESS, |
| 64 | .min_input_signal_level = 0, |
| 65 | .max_input_signal_level = 255, |
| 66 | }; |
| 67 | |
| 68 | /* Scope (\_SB.PCI0.PBRA.IGFX) */ |
| 69 | acpigen_write_scope(acpi_device_path(dev)); |
| 70 | /* Method (ATIF, 2, NotSerialized) */ |
| 71 | acpigen_write_method("ATIF", 2); |
| 72 | /* ToInteger (Arg0, Local0) */ |
| 73 | acpigen_write_to_integer(ARG0_OP, LOCAL0_OP); |
| 74 | |
| 75 | /* If ((Local0 == Zero)) */ |
| 76 | acpigen_write_if_lequal_op_int(LOCAL0_OP, ATIF_FUNCTION_VERIFY_INTERFACE); |
| 77 | /* Return (Buffer (0x0C) { ... } */ |
| 78 | acpigen_write_return_byte_buffer((uint8_t *)(void *)&verify_output, |
| 79 | sizeof(verify_output)); |
Aaron Durbin | 77a062e | 2020-08-20 10:15:06 -0600 | [diff] [blame] | 80 | |
| 81 | /* ElseIf ((Local0 == 0x10)) */ |
| 82 | acpigen_write_else(); |
| 83 | acpigen_write_if_lequal_op_int(LOCAL0_OP, |
| 84 | ATIF_FUNCTION_QUERY_BRIGHTNESS_TRANSFER_CHARACTERISTICS); |
| 85 | /* CreateByteField (Arg1, 0x02, DISP) */ |
| 86 | acpigen_write_create_byte_field(ARG1_OP, |
| 87 | offsetof(struct atif_brightness_input, requested_display), "DISP"); |
| 88 | /* ToInteger (DISP, Local1) */ |
| 89 | acpigen_write_to_integer_from_namestring("DISP", LOCAL1_OP); |
| 90 | /* If ((Local1 == Zero)) */ |
| 91 | acpigen_write_if_lequal_op_int(LOCAL1_OP, ATIF_QBTC_REQUEST_LCD1); |
| 92 | /* Return (Buffer (0x0A) { ... } */ |
| 93 | acpigen_write_return_byte_buffer((uint8_t *)(void *)&brightness_out, |
| 94 | sizeof(brightness_out)); |
Aaron Durbin | 77a062e | 2020-08-20 10:15:06 -0600 | [diff] [blame] | 95 | /* Else */ |
| 96 | acpigen_write_else(); |
| 97 | /* Return (Buffer (0x0A) */ |
| 98 | acpigen_write_return_byte_buffer((uint8_t *)(void *)&brightness_error, |
| 99 | sizeof(brightness_error)); |
| 100 | acpigen_pop_len(); /* else */ |
| 101 | |
| 102 | acpigen_pop_len(); /* if (LEqual(Local0, 0x10) */ |
| 103 | acpigen_pop_len(); /* else */ |
| 104 | |
| 105 | acpigen_pop_len(); /* Method */ |
| 106 | acpigen_pop_len(); /* Scope */ |
| 107 | } |
| 108 | |
Raul E Rangel | da5e07e | 2020-04-29 15:55:33 -0600 | [diff] [blame] | 109 | static void graphics_fill_ssdt(const struct device *dev) |
Furquan Shaikh | f939df7 | 2020-04-23 14:13:02 -0700 | [diff] [blame] | 110 | { |
| 111 | acpi_device_write_pci_dev(dev); |
Raul E Rangel | a7659eb | 2021-03-16 13:20:23 -0600 | [diff] [blame] | 112 | |
| 113 | /* Use the VFCT copy when using GOP */ |
| 114 | if (!CONFIG(RUN_FSP_GOP)) |
| 115 | pci_rom_ssdt(dev); |
| 116 | |
Aaron Durbin | 77a062e | 2020-08-20 10:15:06 -0600 | [diff] [blame] | 117 | if (CONFIG(SOC_AMD_COMMON_BLOCK_GRAPHICS_ATIF)) |
| 118 | generate_atif(dev); |
Furquan Shaikh | f939df7 | 2020-04-23 14:13:02 -0700 | [diff] [blame] | 119 | } |
| 120 | |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 121 | static const char *graphics_acpi_name(const struct device *dev) |
| 122 | { |
| 123 | return "IGFX"; |
| 124 | } |
| 125 | |
Nikolai Vyssotski | ad68e69 | 2021-01-15 11:39:33 -0600 | [diff] [blame] | 126 | /* |
| 127 | * Even though AMD does not need VBT we still need to implement the |
| 128 | * vbt_get() function to not break the build with GOP driver enabled |
| 129 | * (see fsps_return_value_handler() in fsp2_0/silicon_init.c |
| 130 | */ |
| 131 | void *vbt_get(void) |
| 132 | { |
| 133 | return NULL; |
| 134 | } |
| 135 | |
Nikolai Vyssotski | b649d6a | 2021-03-11 19:15:03 -0600 | [diff] [blame] | 136 | static void graphics_set_resources(struct device *const dev) |
| 137 | { |
| 138 | struct rom_header *rom, *ram; |
| 139 | |
| 140 | pci_dev_set_resources(dev); |
| 141 | |
| 142 | if (!CONFIG(RUN_FSP_GOP)) |
| 143 | return; |
| 144 | |
| 145 | timestamp_add_now(TS_OPROM_INITIALIZE); |
| 146 | rom = pci_rom_probe(dev); |
| 147 | if (rom == NULL) |
| 148 | return; |
| 149 | ram = pci_rom_load(dev, rom); |
| 150 | if (ram == NULL) |
| 151 | return; |
| 152 | timestamp_add_now(TS_OPROM_COPY_END); |
| 153 | } |
| 154 | |
Nikolai Vyssotski | 95675d9 | 2021-02-09 13:01:07 -0600 | [diff] [blame] | 155 | static void graphics_dev_init(struct device *const dev) |
| 156 | { |
| 157 | if (CONFIG(RUN_FSP_GOP)) { |
| 158 | struct resource *res = probe_resource(dev, PCI_BASE_ADDRESS_0); |
| 159 | |
| 160 | if (res && res->base) |
Tim Wawrzynczak | 84428f7 | 2021-09-14 13:59:33 -0600 | [diff] [blame] | 161 | fsp_report_framebuffer_info(res->base, LB_FB_ORIENTATION_NORMAL); |
Nikolai Vyssotski | 95675d9 | 2021-02-09 13:01:07 -0600 | [diff] [blame] | 162 | else |
| 163 | printk(BIOS_ERR, "%s: Unable to find resource for %s\n", |
| 164 | __func__, dev_path(dev)); |
| 165 | } |
| 166 | |
| 167 | /* Initialize PCI device, load/execute BIOS Option ROM */ |
| 168 | pci_dev_init(dev); |
| 169 | } |
| 170 | |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 171 | static const struct device_operations graphics_ops = { |
| 172 | .read_resources = pci_dev_read_resources, |
Nikolai Vyssotski | b649d6a | 2021-03-11 19:15:03 -0600 | [diff] [blame] | 173 | .set_resources = graphics_set_resources, |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 174 | .enable_resources = pci_dev_enable_resources, |
Nikolai Vyssotski | 95675d9 | 2021-02-09 13:01:07 -0600 | [diff] [blame] | 175 | .init = graphics_dev_init, |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 176 | .ops_pci = &pci_dev_ops_pci, |
| 177 | .write_acpi_tables = pci_rom_write_acpi_tables, |
Furquan Shaikh | f939df7 | 2020-04-23 14:13:02 -0700 | [diff] [blame] | 178 | .acpi_fill_ssdt = graphics_fill_ssdt, |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 179 | .acpi_name = graphics_acpi_name, |
| 180 | }; |
| 181 | |
| 182 | static const unsigned short pci_device_ids[] = { |
Felix Held | 2b48a60 | 2020-11-18 13:01:00 +0100 | [diff] [blame] | 183 | PCI_DEVICE_ID_ATI_FAM17H_MODEL18H_GPU, |
Felix Held | 3d1fff9 | 2021-10-26 19:41:26 +0200 | [diff] [blame] | 184 | PCI_DEVICE_ID_ATI_FAM17H_MODEL60H_GPU, |
| 185 | PCI_DEVICE_ID_ATI_FAM17H_MODEL68H_GPU, |
Felix Held | caa83ab | 2021-11-09 00:55:38 +0100 | [diff] [blame] | 186 | PCI_DEVICE_ID_ATI_FAM17H_MODELA0H_GPU, |
Felix Held | e6dd5dc | 2021-07-16 22:36:21 +0200 | [diff] [blame] | 187 | PCI_DEVICE_ID_ATI_FAM19H_MODEL51H_GPU_CEZANNE, |
| 188 | PCI_DEVICE_ID_ATI_FAM19H_MODEL51H_GPU_BARCELO, |
Furquan Shaikh | c82aabc | 2020-04-23 13:59:00 -0700 | [diff] [blame] | 189 | 0, |
| 190 | }; |
| 191 | |
| 192 | static const struct pci_driver graphics_driver __pci_driver = { |
| 193 | .ops = &graphics_ops, |
| 194 | .vendor = PCI_VENDOR_ID_ATI, |
| 195 | .devices = pci_device_ids, |
| 196 | }; |