[airlied: add two missing Kconfig] drm-misc-next for v5.18: UAPI Changes: - Fix invalid IN_FORMATS blob when plane->format_mod_supported is NULL. Cross-subsystem Changes: - Assorted dt bindings updates. - Fix vga16fb vga checking on x86. - Fix extra semicolon in rwsem.h's _down_write_nest_lock. - Assorted small fixes to agp and fbdev drivers. - Fix oops in creating a udmabuf with 0 pages. - Hot-unplug firmware fb devices on forced removal - Reqquest memory region in simplefb and simpledrm, and don't make the ioresource as busy. Core Changes: - Mock a drm_plane in drm-plane-helper selftest. - Assorted bug fixes to device logging, dbi. - Use DP helper for sink count in mst. - Assorted documentation fixes. - Assorted small fixes. - Move DP headers to drm/dp, and add a drm dp helper module. - Move the buddy allocator from i915 to common drm. - Add simple pci and platform module init macros to remove a lot of boilerplate from some drivers. - Support microsoft extension for HMDs and specialized monitors. - Improve edid parser's deep color handling. - Add type 7 timing support to edid parser. - Add a weak backpointer to the ttm_bo from ttm_resource - Add 3 eDP panels. Driver Changes: - Add support for HDMI and JZ4780 to ingenic. - Add support for higher DP/eDP bitrates to nouveau. - Assorted driver fixes to tilcdc, vmwgfx, sn65dsi83, meson, stm, panfrost, v3d, gma500, vc4, virtio, mgag200, ast, radeon, amdgpu, nouveau, various bridge drivers. - Convert and revert exynos dsi support to bridge driver. - Add vcc supply regulator support for sn65dsi83. - More conversion of bridge/chipone-icn6211 to atomic. - Remove conflicting fb's from stm, and add support for new hw version. - Add device link in parade-ps8640 to fix suspend/resume. - Update Boe-tv110c9m init sequence. - Add wide screen support to AST2600. - Fix omapdrm implicit dma_buf fencing. - Add support for multiple overlay planes to vkms. - Convert bridge/anx7625 to atomic, add HDCP support, add eld support for audio, and fix HPD. - Add driver for ChromeOS privacy screen. - Handover display from firmware to vc4 more gracefully, and support nomodeset. - Add flexible and ycbcr pixel formats to stm/ltdc. - Convert exynos mipi dsi to atomic. - Add initial dual core group GPUs support to panfrost. - No longer add exclusive fence in amdgpu as shared fence. - Add CSC and full range supoprt to vc4. - Shutdown the display on system shutdown and unbind. - Add Multi-Inno Technology MI0700S4T-6 simple panel. Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -39,6 +39,7 @@ properties: · 38 unmodified lines | |||
| 39 | - const: lvds-encoder # Generic LVDS encoder compatible fallback | 39 | - const: lvds-encoder # Generic LVDS encoder compatible fallback |
| 40 | - items: | 40 | - items: |
| 41 | - enum: | 41 | - enum: |
| 42 | - ti,ds90cf364a # For the DS90CF364A FPD-Link LVDS Receiver | ||
| 42 | - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver | 43 | - ti,ds90cf384a # For the DS90CF384A FPD-Link LVDS Receiver |
| 43 | - const: lvds-decoder # Generic LVDS decoders compatible fallback | 44 | - const: lvds-decoder # Generic LVDS decoders compatible fallback |
| 44 | - enum: | 45 | - enum: |
| @@ -32,6 +32,9 @@ properties: · 31 unmodified lines | |||
| 32 | maxItems: 1 | 32 | maxItems: 1 |
| 33 | description: GPIO specifier for bridge_en pin (active high). | 33 | description: GPIO specifier for bridge_en pin (active high). |
| 34 | 34 | ||
| 35 | vcc-supply: | ||
| 36 | description: A 1.8V power supply (see regulator/regulator.yaml). | ||
| 37 | |||
| 35 | ports: | 38 | ports: |
| 36 | $ref: /schemas/graph.yaml#/properties/ports | 39 | $ref: /schemas/graph.yaml#/properties/ports |
| 37 | 40 | ||
| @@ -91,7 +94,6 @@ properties: · 53 unmodified lines | |||
| 91 | required: | 94 | required: |
| 92 | - compatible | 95 | - compatible |
| 93 | - reg | 96 | - reg |
| 94 | - enable-gpios | ||
| 95 | - ports | 97 | - ports |
| 96 | 98 | ||
| 97 | allOf: | 99 | allOf: |
| @@ -133,6 +135,7 @@ examples: · 35 unmodified lines | |||
| 133 | reg = <0x2d>; | 135 | reg = <0x2d>; |
| 134 | 136 | ||
| 135 | enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; | 137 | enable-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>; |
| 138 | vcc-supply = <®_sn65dsi83_1v8>; | ||
| 136 | 139 | ||
| 137 | ports { | 140 | ports { |
| 138 | #address-cells = <1>; | 141 | #address-cells = <1>; |
| @@ -222,6 +222,8 @@ properties: · 221 unmodified lines | |||
| 222 | - logictechno,lttd800480070-l6wh-rt | 222 | - logictechno,lttd800480070-l6wh-rt |
| 223 | # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel | 223 | # Mitsubishi "AA070MC01 7.0" WVGA TFT LCD panel |
| 224 | - mitsubishi,aa070mc01-ca1 | 224 | - mitsubishi,aa070mc01-ca1 |
| 225 | # Multi-Inno Technology Co.,Ltd MI0700S4T-6 7" 800x480 TFT Resistive Touch Module | ||
| 226 | - multi-inno,mi0700s4t-6 | ||
| 225 | # Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod. | 227 | # Multi-Inno Technology Co.,Ltd MI1010AIT-1CP 10.1" 1280x800 LVDS IPS Cap Touch Mod. |
| 226 | - multi-inno,mi1010ait-1cp | 228 | - multi-inno,mi1010ait-1cp |
| 227 | # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel | 229 | # NEC LCD Technologies, Ltd. 12.1" WXGA (1280x800) LVDS TFT LCD panel |
| @@ -4,7 +4,12 @@ · 3 unmodified lines | |||
| 4 | $id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# | 4 | $id: http://devicetree.org/schemas/display/panel/sony,acx424akp.yaml# |
| 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | ||
| 7 | title: Sony ACX424AKP 4" 480x864 AMOLED panel | 7 | title: Sony ACX424AKP/ACX424AKM 4" 480x864/480x854 AMOLED panel |
| 8 | |||
| 9 | description: The Sony ACX424AKP and ACX424AKM are panels built around | ||
| 10 | the Novatek NT35560 display controller. The only difference is that | ||
| 11 | the AKM is configured to use 10 pixels less in the Y axis than the | ||
| 12 | AKP. | ||
| 8 | 13 | ||
| 9 | maintainers: | 14 | maintainers: |
| 10 | - Linus Walleij <linus.walleij@linaro.org> | 15 | - Linus Walleij <linus.walleij@linaro.org> |
| @@ -14,7 +19,9 @@ allOf: · 3 unmodified lines | |||
| 14 | 19 | ||
| 15 | properties: | 20 | properties: |
| 16 | compatible: | 21 | compatible: |
| 17 | const: sony,acx424akp | 22 | enum: |
| 23 | - sony,acx424akp | ||
| 24 | - sony,acx424akm | ||
| 18 | reg: true | 25 | reg: true |
| 19 | reset-gpios: true | 26 | reset-gpios: true |
| 20 | vddi-supply: | 27 | vddi-supply: |
| @@ -75,6 +75,12 @@ update it, its value is mostly useless. The DRM core prints it to the · 74 unmodified lines | |||
| 75 | kernel log at initialization time and passes it to userspace through the | 75 | kernel log at initialization time and passes it to userspace through the |
| 76 | DRM_IOCTL_VERSION ioctl. | 76 | DRM_IOCTL_VERSION ioctl. |
| 77 | 77 | ||
| 78 | Module Initialization | ||
| 79 | --------------------- | ||
| 80 | |||
| 81 | .. kernel-doc:: include/drm/drm_module.h | ||
| 82 | :doc: overview | ||
| 83 | |||
| 78 | Managing Ownership of the Framebuffer Aperture | 84 | Managing Ownership of the Framebuffer Aperture |
| 79 | ---------------------------------------------- | 85 | ---------------------------------------------- |
| 80 | 86 | ||
| @@ -232,34 +232,34 @@ HDCP Helper Functions Reference · 231 unmodified lines | |||
| 232 | Display Port Helper Functions Reference | 232 | Display Port Helper Functions Reference |
| 233 | ======================================= | 233 | ======================================= |
| 234 | 234 | ||
| 235 | .. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c | 235 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c |
| 236 | :doc: dp helpers | 236 | :doc: dp helpers |
| 237 | 237 | ||
| 238 | .. kernel-doc:: include/drm/drm_dp_helper.h | 238 | .. kernel-doc:: include/drm/dp/drm_dp_helper.h |
| 239 | :internal: | 239 | :internal: |
| 240 | 240 | ||
| 241 | .. kernel-doc:: drivers/gpu/drm/drm_dp_helper.c | 241 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp.c |
| 242 | :export: | 242 | :export: |
| 243 | 243 | ||
| 244 | Display Port CEC Helper Functions Reference | 244 | Display Port CEC Helper Functions Reference |
| 245 | =========================================== | 245 | =========================================== |
| 246 | 246 | ||
| 247 | .. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c | 247 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c |
| 248 | :doc: dp cec helpers | 248 | :doc: dp cec helpers |
| 249 | 249 | ||
| 250 | .. kernel-doc:: drivers/gpu/drm/drm_dp_cec.c | 250 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_cec.c |
| 251 | :export: | 251 | :export: |
| 252 | 252 | ||
| 253 | Display Port Dual Mode Adaptor Helper Functions Reference | 253 | Display Port Dual Mode Adaptor Helper Functions Reference |
| 254 | ========================================================= | 254 | ========================================================= |
| 255 | 255 | ||
| 256 | .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | 256 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c |
| 257 | :doc: dp dual mode helpers | 257 | :doc: dp dual mode helpers |
| 258 | 258 | ||
| 259 | .. kernel-doc:: include/drm/drm_dp_dual_mode_helper.h | 259 | .. kernel-doc:: include/drm/dp/drm_dp_dual_mode_helper.h |
| 260 | :internal: | 260 | :internal: |
| 261 | 261 | ||
| 262 | .. kernel-doc:: drivers/gpu/drm/drm_dp_dual_mode_helper.c | 262 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_dual_mode_helper.c |
| 263 | :export: | 263 | :export: |
| 264 | 264 | ||
| 265 | Display Port MST Helpers | 265 | Display Port MST Helpers |
| @@ -268,19 +268,19 @@ Display Port MST Helpers · 2 unmodified lines | |||
| 268 | Overview | 268 | Overview |
| 269 | -------- | 269 | -------- |
| 270 | 270 | ||
| 271 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | 271 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c |
| 272 | :doc: dp mst helper | 272 | :doc: dp mst helper |
| 273 | 273 | ||
| 274 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | 274 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c |
| 275 | :doc: Branch device and port refcounting | 275 | :doc: Branch device and port refcounting |
| 276 | 276 | ||
| 277 | Functions Reference | 277 | Functions Reference |
| 278 | ------------------- | 278 | ------------------- |
| 279 | 279 | ||
| 280 | .. kernel-doc:: include/drm/drm_dp_mst_helper.h | 280 | .. kernel-doc:: include/drm/dp/drm_dp_mst_helper.h |
| 281 | :internal: | 281 | :internal: |
| 282 | 282 | ||
| 283 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | 283 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c |
| 284 | :export: | 284 | :export: |
| 285 | 285 | ||
| 286 | Topology Lifetime Internals | 286 | Topology Lifetime Internals |
| @@ -289,7 +289,7 @@ Topology Lifetime Internals · 2 unmodified lines | |||
| 289 | These functions aren't exported to drivers, but are documented here to help make | 289 | These functions aren't exported to drivers, but are documented here to help make |
| 290 | the MST topology helpers easier to understand | 290 | the MST topology helpers easier to understand |
| 291 | 291 | ||
| 292 | .. kernel-doc:: drivers/gpu/drm/drm_dp_mst_topology.c | 292 | .. kernel-doc:: drivers/gpu/drm/dp/drm_dp_mst_topology.c |
| 293 | :functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb | 293 | :functions: drm_dp_mst_topology_try_get_mstb drm_dp_mst_topology_get_mstb |
| 294 | drm_dp_mst_topology_put_mstb | 294 | drm_dp_mst_topology_put_mstb |
| 295 | drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port | 295 | drm_dp_mst_topology_try_get_port drm_dp_mst_topology_get_port |
| @@ -423,12 +423,12 @@ Connector Functions Reference · 422 unmodified lines | |||
| 423 | Writeback Connectors | 423 | Writeback Connectors |
| 424 | -------------------- | 424 | -------------------- |
| 425 | 425 | ||
| 426 | .. kernel-doc:: include/drm/drm_writeback.h | ||
| 427 | :internal: | ||
| 428 | |||
| 429 | .. kernel-doc:: drivers/gpu/drm/drm_writeback.c | 426 | .. kernel-doc:: drivers/gpu/drm/drm_writeback.c |
| 430 | :doc: overview | 427 | :doc: overview |
| 431 | 428 | ||
| 429 | .. kernel-doc:: include/drm/drm_writeback.h | ||
| 430 | :internal: | ||
| 431 | |||
| 432 | .. kernel-doc:: drivers/gpu/drm/drm_writeback.c | 432 | .. kernel-doc:: drivers/gpu/drm/drm_writeback.c |
| 433 | :export: | 433 | :export: |
| 434 | 434 | ||
| @@ -8,7 +8,7 @@ the very dynamic nature of many of that data, managing graphics memory · 7 unmodified lines | |||
| 8 | efficiently is thus crucial for the graphics stack and plays a central | 8 | efficiently is thus crucial for the graphics stack and plays a central |
| 9 | role in the DRM infrastructure. | 9 | role in the DRM infrastructure. |
| 10 | 10 | ||
| 11 | The DRM core includes two memory managers, namely Translation Table Maps | 11 | The DRM core includes two memory managers, namely Translation Table Manager |
| 12 | (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory | 12 | (TTM) and Graphics Execution Manager (GEM). TTM was the first DRM memory |
| 13 | manager to be developed and tried to be a one-size-fits-them all | 13 | manager to be developed and tried to be a one-size-fits-them all |
| 14 | solution. It provides a single userspace API to accommodate the need of | 14 | solution. It provides a single userspace API to accommodate the need of |
| @@ -467,6 +467,21 @@ Contact: Thomas Zimmermann <tzimmermann@suse.de> · 466 unmodified lines | |||
| 467 | 467 | ||
| 468 | Level: Intermediate | 468 | Level: Intermediate |
| 469 | 469 | ||
| 470 | Request memory regions in all drivers | ||
| 471 | ------------------------------------- | ||
| 472 | |||
| 473 | Go through all drivers and add code to request the memory regions that the | ||
| 474 | driver uses. This requires adding calls to request_mem_region(), | ||
| 475 | pci_request_region() or similar functions. Use helpers for managed cleanup | ||
| 476 | where possible. | ||
| 477 | |||
| 478 | Drivers are pretty bad at doing this and there used to be conflicts among | ||
| 479 | DRM and fbdev drivers. Still, it's the correct thing to do. | ||
| 480 | |||
| 481 | Contact: Thomas Zimmermann <tzimmermann@suse.de> | ||
| 482 | |||
| 483 | Level: Starter | ||
| 484 | |||
| 470 | 485 | ||
| 471 | Core refactorings | 486 | Core refactorings |
| 472 | ================= | 487 | ================= |
| @@ -124,8 +124,6 @@ Add Plane Features · 123 unmodified lines | |||
| 124 | 124 | ||
| 125 | There's lots of plane features we could add support for: | 125 | There's lots of plane features we could add support for: |
| 126 | 126 | ||
| 127 | - Multiple overlay planes. [Good to get started] | ||
| 128 | |||
| 129 | - Clearing primary plane: clear primary plane before plane composition (at the | 127 | - Clearing primary plane: clear primary plane before plane composition (at the |
| 130 | start) for correctness of pixel blend ops. It also guarantees alpha channel | 128 | start) for correctness of pixel blend ops. It also guarantees alpha channel |
| 131 | is cleared in the target buffer for stable crc. [Good to get started] | 129 | is cleared in the target buffer for stable crc. [Good to get started] |
| @@ -55,7 +55,7 @@ static struct _ati_generic_private { · 54 unmodified lines | |||
| 55 | 55 | ||
| 56 | static int ati_create_page_map(struct ati_page_map *page_map) | 56 | static int ati_create_page_map(struct ati_page_map *page_map) |
| 57 | { | 57 | { |
| 58 | int i, err = 0; | 58 | int i, err; |
| 59 | 59 | ||
| 60 | page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); | 60 | page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL); |
| 61 | if (page_map->real == NULL) | 61 | if (page_map->real == NULL) |
| @@ -63,6 +63,10 @@ static int ati_create_page_map(struct ati_page_map *page_map) · 1 unmodified line | |||
| 63 | 63 | ||
| 64 | set_memory_uc((unsigned long)page_map->real, 1); | 64 | set_memory_uc((unsigned long)page_map->real, 1); |
| 65 | err = map_page_into_agp(virt_to_page(page_map->real)); | 65 | err = map_page_into_agp(virt_to_page(page_map->real)); |
| 66 | if (err) { | ||
| 67 | free_page((unsigned long)page_map->real); | ||
| 68 | return err; | ||
| 69 | } | ||
| 66 | page_map->remapped = page_map->real; | 70 | page_map->remapped = page_map->real; |
| 67 | 71 | ||
| 68 | for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { | 72 | for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) { |
| @@ -303,7 +307,7 @@ static int ati_insert_memory(struct agp_memory * mem, · 234 unmodified lines | |||
| 303 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { | 307 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { |
| 304 | addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; | 308 | addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; |
| 305 | cur_gatt = GET_GATT(addr); | 309 | cur_gatt = GET_GATT(addr); |
| 306 | writel(agp_bridge->driver->mask_memory(agp_bridge, | 310 | writel(agp_bridge->driver->mask_memory(agp_bridge, |
| 307 | page_to_phys(mem->pages[i]), | 311 | page_to_phys(mem->pages[i]), |
| 308 | mem->type), | 312 | mem->type), |
| 309 | cur_gatt+GET_GATT_OFF(addr)); | 313 | cur_gatt+GET_GATT_OFF(addr)); |
| @@ -62,6 +62,7 @@ EXPORT_SYMBOL(agp_find_bridge); · 61 unmodified lines | |||
| 62 | 62 | ||
| 63 | /** | 63 | /** |
| 64 | * agp_backend_acquire - attempt to acquire an agp backend. | 64 | * agp_backend_acquire - attempt to acquire an agp backend. |
| 65 | * @pdev: the PCI device | ||
| 65 | * | 66 | * |
| 66 | */ | 67 | */ |
| 67 | struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev) | 68 | struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev) |
| @@ -83,6 +84,7 @@ EXPORT_SYMBOL(agp_backend_acquire); · 15 unmodified lines | |||
| 83 | 84 | ||
| 84 | /** | 85 | /** |
| 85 | * agp_backend_release - release the lock on the agp backend. | 86 | * agp_backend_release - release the lock on the agp backend. |
| 87 | * @bridge: the AGP backend to release | ||
| 86 | * | 88 | * |
| 87 | * The caller must insure that the graphics aperture translation table | 89 | * The caller must insure that the graphics aperture translation table |
| 88 | * is read for use by another entity. | 90 | * is read for use by another entity. |
| @@ -39,7 +39,9 @@ · 38 unmodified lines | |||
| 39 | #include <linux/fs.h> | 39 | #include <linux/fs.h> |
| 40 | #include <linux/sched.h> | 40 | #include <linux/sched.h> |
| 41 | #include <linux/uaccess.h> | 41 | #include <linux/uaccess.h> |
| 42 | |||
| 42 | #include "agp.h" | 43 | #include "agp.h" |
| 44 | #include "compat_ioctl.h" | ||
| 43 | 45 | ||
| 44 | struct agp_front_data agp_fe; | 46 | struct agp_front_data agp_fe; |
| 45 | 47 | ||
| @@ -1017,7 +1019,7 @@ static long agp_ioctl(struct file *file, · 971 unmodified lines | |||
| 1017 | case AGPIOC_UNBIND: | 1019 | case AGPIOC_UNBIND: |
| 1018 | ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); | 1020 | ret_val = agpioc_unbind_wrap(curr_priv, (void __user *) arg); |
| 1019 | break; | 1021 | break; |
| 1020 | 1022 | ||
| 1021 | case AGPIOC_CHIPSET_FLUSH: | 1023 | case AGPIOC_CHIPSET_FLUSH: |
| 1022 | break; | 1024 | break; |
| 1023 | } | 1025 | } |
| @@ -261,7 +261,8 @@ static int nvidia_remove_memory(struct agp_memory *mem, off_t pg_start, int type · 260 unmodified lines | |||
| 261 | static void nvidia_tlbflush(struct agp_memory *mem) | 261 | static void nvidia_tlbflush(struct agp_memory *mem) |
| 262 | { | 262 | { |
| 263 | unsigned long end; | 263 | unsigned long end; |
| 264 | u32 wbc_reg, temp; | 264 | u32 wbc_reg; |
| 265 | u32 __maybe_unused temp; | ||
| 265 | int i; | 266 | int i; |
| 266 | 267 | ||
| 267 | /* flush chipset */ | 268 | /* flush chipset */ |
| @@ -262,13 +262,10 @@ static void serverworks_tlbflush(struct agp_memory *temp) · 261 unmodified lines | |||
| 262 | 262 | ||
| 263 | static int serverworks_configure(void) | 263 | static int serverworks_configure(void) |
| 264 | { | 264 | { |
| 265 | struct aper_size_info_lvl2 *current_size; | ||
| 266 | u32 temp; | 265 | u32 temp; |
| 267 | u8 enable_reg; | 266 | u8 enable_reg; |
| 268 | u16 cap_reg; | 267 | u16 cap_reg; |
| 269 | 268 | ||
| 270 | current_size = A_SIZE_LVL2(agp_bridge->current_size); | ||
| 271 | |||
| 272 | /* Get the memory mapped registers */ | 269 | /* Get the memory mapped registers */ |
| 273 | pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp); | 270 | pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp); |
| 274 | temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); | 271 | temp = (temp & PCI_BASE_ADDRESS_MEM_MASK); |
| @@ -350,7 +347,7 @@ static int serverworks_insert_memory(struct agp_memory *mem, · 75 unmodified lines | |||
| 350 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { | 347 | for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { |
| 351 | addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; | 348 | addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr; |
| 352 | cur_gatt = SVRWRKS_GET_GATT(addr); | 349 | cur_gatt = SVRWRKS_GET_GATT(addr); |
| 353 | writel(agp_bridge->driver->mask_memory(agp_bridge, | 350 | writel(agp_bridge->driver->mask_memory(agp_bridge, |
| 354 | page_to_phys(mem->pages[i]), mem->type), | 351 | page_to_phys(mem->pages[i]), mem->type), |
| 355 | cur_gatt+GET_GATT_OFF(addr)); | 352 | cur_gatt+GET_GATT_OFF(addr)); |
| 356 | } | 353 | } |
| @@ -128,9 +128,6 @@ static int via_fetch_size_agp3(void) · 127 unmodified lines | |||
| 128 | static int via_configure_agp3(void) | 128 | static int via_configure_agp3(void) |
| 129 | { | 129 | { |
| 130 | u32 temp; | 130 | u32 temp; |
| 131 | struct aper_size_info_16 *current_size; | ||
| 132 | |||
| 133 | current_size = A_SIZE_16(agp_bridge->current_size); | ||
| 134 | 131 | ||
| 135 | /* address to map to */ | 132 | /* address to map to */ |
| 136 | agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, | 133 | agp_bridge->gart_bus_addr = pci_bus_address(agp_bridge->dev, |
| @@ -542,57 +542,45 @@ EXPORT_SYMBOL(dma_resv_copy_fences); · 541 unmodified lines | |||
| 542 | * dma_resv_get_fences - Get an object's shared and exclusive | 542 | * dma_resv_get_fences - Get an object's shared and exclusive |
| 543 | * fences without update side lock held | 543 | * fences without update side lock held |
| 544 | * @obj: the reservation object | 544 | * @obj: the reservation object |
| 545 | * @fence_excl: the returned exclusive fence (or NULL) | 545 | * @write: true if we should return all fences |
| 546 | * @shared_count: the number of shared fences returned | 546 | * @num_fences: the number of fences returned |
| 547 | * @shared: the array of shared fence ptrs returned (array is krealloc'd to | 547 | * @fences: the array of fence ptrs returned (array is krealloc'd to the |
| 548 | * the required size, and must be freed by caller) | 548 | * required size, and must be freed by caller) |
| 549 | * | 549 | * |
| 550 | * Retrieve all fences from the reservation object. If the pointer for the | 550 | * Retrieve all fences from the reservation object. |
| 551 | * exclusive fence is not specified the fence is put into the array of the | 551 | * Returns either zero or -ENOMEM. |
| 552 | * shared fences as well. Returns either zero or -ENOMEM. | ||
| 553 | */ | 552 | */ |
| 554 | int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **fence_excl, | 553 | int dma_resv_get_fences(struct dma_resv *obj, bool write, |
| 555 | unsigned int *shared_count, struct dma_fence ***shared) | 554 | unsigned int *num_fences, struct dma_fence ***fences) |
| 556 | { | 555 | { |
| 557 | struct dma_resv_iter cursor; | 556 | struct dma_resv_iter cursor; |
| 558 | struct dma_fence *fence; | 557 | struct dma_fence *fence; |
| 559 | 558 | ||
| 560 | *shared_count = 0; | 559 | *num_fences = 0; |
| 561 | *shared = NULL; | 560 | *fences = NULL; |
| 562 | 561 | ||
| 563 | if (fence_excl) | 562 | dma_resv_iter_begin(&cursor, obj, write); |
| 564 | *fence_excl = NULL; | ||
| 565 | |||
| 566 | dma_resv_iter_begin(&cursor, obj, true); | ||
| 567 | dma_resv_for_each_fence_unlocked(&cursor, fence) { | 563 | dma_resv_for_each_fence_unlocked(&cursor, fence) { |
| 568 | 564 | ||
| 569 | if (dma_resv_iter_is_restarted(&cursor)) { | 565 | if (dma_resv_iter_is_restarted(&cursor)) { |
| 570 | unsigned int count; | 566 | unsigned int count; |
| 571 | 567 | ||
| 572 | while (*shared_count) | 568 | while (*num_fences) |
| 573 | dma_fence_put((*shared)[--(*shared_count)]); | 569 | dma_fence_put((*fences)[--(*num_fences)]); |
| 574 | |||
| 575 | if (fence_excl) | ||
| 576 | dma_fence_put(*fence_excl); | ||
| 577 | 570 | ||
| 578 | count = cursor.shared_count; | 571 | count = cursor.shared_count + 1; |
| 579 | count += fence_excl ? 0 : 1; | ||
| 580 | 572 | ||
| 581 | /* Eventually re-allocate the array */ | 573 | /* Eventually re-allocate the array */ |
| 582 | *shared = krealloc_array(*shared, count, | 574 | *fences = krealloc_array(*fences, count, |
| 583 | sizeof(void *), | 575 | sizeof(void *), |
| 584 | GFP_KERNEL); | 576 | GFP_KERNEL); |
| 585 | if (count && !*shared) { | 577 | if (count && !*fences) { |
| 586 | dma_resv_iter_end(&cursor); | 578 | dma_resv_iter_end(&cursor); |
| 587 | return -ENOMEM; | 579 | return -ENOMEM; |
| 588 | } | 580 | } |
| 589 | } | 581 | } |
| 590 | 582 | ||
| 591 | dma_fence_get(fence); | 583 | (*fences)[(*num_fences)++] = dma_fence_get(fence); |
| 592 | if (dma_resv_iter_is_exclusive(&cursor) && fence_excl) | ||
| 593 | *fence_excl = fence; | ||
| 594 | else | ||
| 595 | (*shared)[(*shared_count)++] = fence; | ||
| 596 | } | 584 | } |
| 597 | dma_resv_iter_end(&cursor); | 585 | dma_resv_iter_end(&cursor); |
| 598 | 586 | ||
| @@ -275,7 +275,7 @@ static int test_shared_for_each_unlocked(void *arg) · 274 unmodified lines | |||
| 275 | 275 | ||
| 276 | static int test_get_fences(void *arg, bool shared) | 276 | static int test_get_fences(void *arg, bool shared) |
| 277 | { | 277 | { |
| 278 | struct dma_fence *f, *excl = NULL, **fences = NULL; | 278 | struct dma_fence *f, **fences = NULL; |
| 279 | struct dma_resv resv; | 279 | struct dma_resv resv; |
| 280 | int r, i; | 280 | int r, i; |
| 281 | 281 | ||
| @@ -304,35 +304,19 @@ static int test_get_fences(void *arg, bool shared) · 22 unmodified lines | |||
| 304 | } | 304 | } |
| 305 | dma_resv_unlock(&resv); | 305 | dma_resv_unlock(&resv); |
| 306 | 306 | ||
| 307 | r = dma_resv_get_fences(&resv, &excl, &i, &fences); | 307 | r = dma_resv_get_fences(&resv, shared, &i, &fences); |
| 308 | if (r) { | 308 | if (r) { |
| 309 | pr_err("get_fences failed\n"); | 309 | pr_err("get_fences failed\n"); |
| 310 | goto err_free; | 310 | goto err_free; |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | if (shared) { | 313 | if (i != 1 || fences[0] != f) { |
| 314 | if (excl != NULL) { | 314 | pr_err("get_fences returned unexpected fence\n"); |
| 315 | pr_err("get_fences returned unexpected excl fence\n"); | 315 | goto err_free; |
| 316 | goto err_free; | ||
| 317 | } | ||
| 318 | if (i != 1 || fences[0] != f) { | ||
| 319 | pr_err("get_fences returned unexpected shared fence\n"); | ||
| 320 | goto err_free; | ||
| 321 | } | ||
| 322 | } else { | ||
| 323 | if (excl != f) { | ||
| 324 | pr_err("get_fences returned unexpected excl fence\n"); | ||
| 325 | goto err_free; | ||
| 326 | } | ||
| 327 | if (i != 0) { | ||
| 328 | pr_err("get_fences returned unexpected shared fence\n"); | ||
| 329 | goto err_free; | ||
| 330 | } | ||
| 331 | } | 316 | } |
| 332 | 317 | ||
| 333 | dma_fence_signal(f); | 318 | dma_fence_signal(f); |
| 334 | err_free: | 319 | err_free: |
| 335 | dma_fence_put(excl); | ||
| 336 | while (i--) | 320 | while (i--) |
| 337 | dma_fence_put(fences[i]); | 321 | dma_fence_put(fences[i]); |
| 338 | kfree(fences); | 322 | kfree(fences); |
| @@ -190,6 +190,10 @@ static long udmabuf_create(struct miscdevice *device, · 189 unmodified lines | |||
| 190 | if (ubuf->pagecount > pglimit) | 190 | if (ubuf->pagecount > pglimit) |
| 191 | goto err; | 191 | goto err; |
| 192 | } | 192 | } |
| 193 | |||
| 194 | if (!ubuf->pagecount) | ||
| 195 | goto err; | ||
| 196 | |||
| 193 | ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), | 197 | ubuf->pages = kmalloc_array(ubuf->pagecount, sizeof(*ubuf->pages), |
| 194 | GFP_KERNEL); | 198 | GFP_KERNEL); |
| 195 | if (!ubuf->pages) { | 199 | if (!ubuf->pages) { |
| @@ -99,7 +99,7 @@ __init int sysfb_create_simplefb(const struct screen_info *si, · 98 unmodified lines | |||
| 99 | 99 | ||
| 100 | /* setup IORESOURCE_MEM as framebuffer memory */ | 100 | /* setup IORESOURCE_MEM as framebuffer memory */ |
| 101 | memset(&res, 0, sizeof(res)); | 101 | memset(&res, 0, sizeof(res)); |
| 102 | res.flags = IORESOURCE_MEM | IORESOURCE_BUSY; | 102 | res.flags = IORESOURCE_MEM; |
| 103 | res.name = simplefb_resname; | 103 | res.name = simplefb_resname; |
| 104 | res.start = base; | 104 | res.start = base; |
| 105 | res.end = res.start + length - 1; | 105 | res.end = res.start + length - 1; |
| @@ -68,6 +68,7 @@ config DRM_DEBUG_SELFTEST · 67 unmodified lines | |||
| 68 | depends on DRM | 68 | depends on DRM |
| 69 | depends on DEBUG_KERNEL | 69 | depends on DEBUG_KERNEL |
| 70 | select PRIME_NUMBERS | 70 | select PRIME_NUMBERS |
| 71 | select DRM_DP_HELPER | ||
| 71 | select DRM_LIB_RANDOM | 72 | select DRM_LIB_RANDOM |
| 72 | select DRM_KMS_HELPER | 73 | select DRM_KMS_HELPER |
| 73 | select DRM_EXPORT_FOR_TESTS if m | 74 | select DRM_EXPORT_FOR_TESTS if m |
| @@ -80,6 +81,12 @@ config DRM_DEBUG_SELFTEST · 6 unmodified lines | |||
| 80 | 81 | ||
| 81 | If in doubt, say "N". | 82 | If in doubt, say "N". |
| 82 | 83 | ||
| 84 | config DRM_DP_HELPER | ||
| 85 | tristate | ||
| 86 | depends on DRM | ||
| 87 | help | ||
| 88 | DRM helpers for DisplayPort. | ||
| 89 | |||
| 83 | config DRM_KMS_HELPER | 90 | config DRM_KMS_HELPER |
| 84 | tristate | 91 | tristate |
| 85 | depends on DRM | 92 | depends on DRM |
| @@ -198,6 +205,12 @@ config DRM_TTM · 112 unmodified lines | |||
| 198 | GPU memory types. Will be enabled automatically if a device driver | 205 | GPU memory types. Will be enabled automatically if a device driver |
| 199 | uses it. | 206 | uses it. |
| 200 | 207 | ||
| 208 | config DRM_BUDDY | ||
| 209 | tristate | ||
| 210 | depends on DRM | ||
| 211 | help | ||
| 212 | A page based buddy allocator | ||
| 213 | |||
| 201 | config DRM_VRAM_HELPER | 214 | config DRM_VRAM_HELPER |
| 202 | tristate | 215 | tristate |
| 203 | depends on DRM | 216 | depends on DRM |
| @@ -236,6 +249,7 @@ config DRM_RADEON · 32 unmodified lines | |||
| 236 | depends on DRM && PCI && MMU | 249 | depends on DRM && PCI && MMU |
| 237 | depends on AGP || !AGP | 250 | depends on AGP || !AGP |
| 238 | select FW_LOADER | 251 | select FW_LOADER |
| 252 | select DRM_DP_HELPER | ||
| 239 | select DRM_KMS_HELPER | 253 | select DRM_KMS_HELPER |
| 240 | select DRM_TTM | 254 | select DRM_TTM |
| 241 | select DRM_TTM_HELPER | 255 | select DRM_TTM_HELPER |
| @@ -256,6 +270,7 @@ config DRM_AMDGPU · 14 unmodified lines | |||
| 256 | tristate "AMD GPU" | 270 | tristate "AMD GPU" |
| 257 | depends on DRM && PCI && MMU | 271 | depends on DRM && PCI && MMU |
| 258 | select FW_LOADER | 272 | select FW_LOADER |
| 273 | select DRM_DP_HELPER | ||
| 259 | select DRM_KMS_HELPER | 274 | select DRM_KMS_HELPER |
| 260 | select DRM_SCHED | 275 | select DRM_SCHED |
| 261 | select DRM_TTM | 276 | select DRM_TTM |
| @@ -31,8 +31,6 @@ drm-$(CONFIG_DEBUG_FS) += drm_debugfs.o drm_debugfs_crc.o · 30 unmodified lines | |||
| 31 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o | 31 | drm-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o |
| 32 | drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o | 32 | drm-$(CONFIG_DRM_PRIVACY_SCREEN) += drm_privacy_screen.o drm_privacy_screen_x86.o |
| 33 | 33 | ||
| 34 | obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | ||
| 35 | |||
| 36 | obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o | 34 | obj-$(CONFIG_DRM_NOMODESET) += drm_nomodeset.o |
| 37 | 35 | ||
| 38 | drm_cma_helper-y := drm_gem_cma_helper.o | 36 | drm_cma_helper-y := drm_gem_cma_helper.o |
| @@ -42,27 +40,26 @@ obj-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_cma_helper.o · 3 unmodified lines | |||
| 42 | drm_shmem_helper-y := drm_gem_shmem_helper.o | 40 | drm_shmem_helper-y := drm_gem_shmem_helper.o |
| 43 | obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o | 41 | obj-$(CONFIG_DRM_GEM_SHMEM_HELPER) += drm_shmem_helper.o |
| 44 | 42 | ||
| 43 | obj-$(CONFIG_DRM_BUDDY) += drm_buddy.o | ||
| 44 | |||
| 45 | drm_vram_helper-y := drm_gem_vram_helper.o | 45 | drm_vram_helper-y := drm_gem_vram_helper.o |
| 46 | obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o | 46 | obj-$(CONFIG_DRM_VRAM_HELPER) += drm_vram_helper.o |
| 47 | 47 | ||
| 48 | drm_ttm_helper-y := drm_gem_ttm_helper.o | 48 | drm_ttm_helper-y := drm_gem_ttm_helper.o |
| 49 | obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o | 49 | obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o |
| 50 | 50 | ||
| 51 | drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o drm_dp_helper.o \ | 51 | drm_kms_helper-y := drm_bridge_connector.o drm_crtc_helper.o \ |
| 52 | drm_dsc.o drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \ | 52 | drm_dsc.o drm_encoder_slave.o drm_flip_work.o drm_hdcp.o \ |
| 53 | drm_probe_helper.o \ | 53 | drm_probe_helper.o \ |
| 54 | drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ | 54 | drm_plane_helper.o drm_atomic_helper.o \ |
| 55 | drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ | 55 | drm_kms_helper_common.o \ |
| 56 | drm_simple_kms_helper.o drm_modeset_helper.o \ | 56 | drm_simple_kms_helper.o drm_modeset_helper.o \ |
| 57 | drm_scdc_helper.o drm_gem_atomic_helper.o \ | 57 | drm_scdc_helper.o drm_gem_atomic_helper.o \ |
| 58 | drm_gem_framebuffer_helper.o \ | 58 | drm_gem_framebuffer_helper.o \ |
| 59 | drm_atomic_state_helper.o drm_damage_helper.o \ | 59 | drm_atomic_state_helper.o drm_damage_helper.o \ |
| 60 | drm_format_helper.o drm_self_refresh_helper.o drm_rect.o | 60 | drm_format_helper.o drm_self_refresh_helper.o drm_rect.o |
| 61 | |||
| 62 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o | 61 | drm_kms_helper-$(CONFIG_DRM_PANEL_BRIDGE) += bridge/panel.o |
| 63 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o | 62 | drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o |
| 64 | drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | ||
| 65 | drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | ||
| 66 | 63 | ||
| 67 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o | 64 | obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o |
| 68 | obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ | 65 | obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/ |
| @@ -72,6 +69,7 @@ obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o · 3 unmodified lines | |||
| 72 | obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o | 69 | obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o |
| 73 | obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o | 70 | obj-$(CONFIG_DRM_PANEL_ORIENTATION_QUIRKS) += drm_panel_orientation_quirks.o |
| 74 | obj-y += arm/ | 71 | obj-y += arm/ |
| 72 | obj-y += dp/ | ||
| 75 | obj-$(CONFIG_DRM_TTM) += ttm/ | 73 | obj-$(CONFIG_DRM_TTM) += ttm/ |
| 76 | obj-$(CONFIG_DRM_SCHED) += scheduler/ | 74 | obj-$(CONFIG_DRM_SCHED) += scheduler/ |
| 77 | obj-$(CONFIG_DRM_TDFX) += tdfx/ | 75 | obj-$(CONFIG_DRM_TDFX) += tdfx/ |
| @@ -26,7 +26,7 @@ · 25 unmodified lines | |||
| 26 | 26 | ||
| 27 | #include <drm/drm_edid.h> | 27 | #include <drm/drm_edid.h> |
| 28 | #include <drm/drm_fb_helper.h> | 28 | #include <drm/drm_fb_helper.h> |
| 29 | #include <drm/drm_dp_helper.h> | 29 | #include <drm/dp/drm_dp_helper.h> |
| 30 | #include <drm/drm_probe_helper.h> | 30 | #include <drm/drm_probe_helper.h> |
| 31 | #include <drm/amdgpu_drm.h> | 31 | #include <drm/amdgpu_drm.h> |
| 32 | #include "amdgpu.h" | 32 | #include "amdgpu.h" |
| @@ -175,7 +175,7 @@ int amdgpu_connector_get_monitor_bpc(struct drm_connector *connector) · 142 unmodified lines | |||
| 175 | 175 | ||
| 176 | /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ | 176 | /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ |
| 177 | if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { | 177 | if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { |
| 178 | if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && | 178 | if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && |
| 179 | (mode_clock * 5/4 <= max_tmds_clock)) | 179 | (mode_clock * 5/4 <= max_tmds_clock)) |
| 180 | bpc = 10; | 180 | bpc = 10; |
| 181 | else | 181 | else |
| @@ -1274,14 +1274,11 @@ static int amdgpu_cs_submit(struct amdgpu_cs_parser *p, · 1273 unmodified lines | |||
| 1274 | /* | 1274 | /* |
| 1275 | * Work around dma_resv shortcommings by wrapping up the | 1275 | * Work around dma_resv shortcommings by wrapping up the |
| 1276 | * submission in a dma_fence_chain and add it as exclusive | 1276 | * submission in a dma_fence_chain and add it as exclusive |
| 1277 | * fence, but first add the submission as shared fence to make | 1277 | * fence. |
| 1278 | * sure that shared fences never signal before the exclusive | ||
| 1279 | * one. | ||
| 1280 | */ | 1278 | */ |
| 1281 | dma_fence_chain_init(chain, dma_resv_excl_fence(resv), | 1279 | dma_fence_chain_init(chain, dma_resv_excl_fence(resv), |
| 1282 | dma_fence_get(p->fence), 1); | 1280 | dma_fence_get(p->fence), 1); |
| 1283 | 1281 | ||
| 1284 | dma_resv_add_shared_fence(resv, p->fence); | ||
| 1285 | rcu_assign_pointer(resv->fence_excl, &chain->base); | 1282 | rcu_assign_pointer(resv->fence_excl, &chain->base); |
| 1286 | e->chain = NULL; | 1283 | e->chain = NULL; |
| 1287 | } | 1284 | } |
| @@ -200,8 +200,10 @@ int amdgpu_display_crtc_page_flip_target(struct drm_crtc *crtc, · 199 unmodified lines | |||
| 200 | goto unpin; | 200 | goto unpin; |
| 201 | } | 201 | } |
| 202 | 202 | ||
| 203 | r = dma_resv_get_fences(new_abo->tbo.base.resv, NULL, | 203 | /* TODO: Unify this with other drivers */ |
| 204 | &work->shared_count, &work->shared); | 204 | r = dma_resv_get_fences(new_abo->tbo.base.resv, true, |
| 205 | &work->shared_count, | ||
| 206 | &work->shared); | ||
| 205 | if (unlikely(r != 0)) { | 207 | if (unlikely(r != 0)) { |
| 206 | DRM_ERROR("failed to get fences for buffer\n"); | 208 | DRM_ERROR("failed to get fences for buffer\n"); |
| 207 | goto unpin; | 209 | goto unpin; |
| @@ -226,12 +226,6 @@ static void amdgpu_gem_object_close(struct drm_gem_object *obj, · 225 unmodified lines | |||
| 226 | if (!amdgpu_vm_ready(vm)) | 226 | if (!amdgpu_vm_ready(vm)) |
| 227 | goto out_unlock; | 227 | goto out_unlock; |
| 228 | 228 | ||
| 229 | fence = dma_resv_excl_fence(bo->tbo.base.resv); | ||
| 230 | if (fence) { | ||
| 231 | amdgpu_bo_fence(bo, fence, true); | ||
| 232 | fence = NULL; | ||
| 233 | } | ||
| 234 | |||
| 235 | r = amdgpu_vm_clear_freed(adev, vm, &fence); | 229 | r = amdgpu_vm_clear_freed(adev, vm, &fence); |
| 236 | if (r || !fence) | 230 | if (r || !fence) |
| 237 | goto out_unlock; | 231 | goto out_unlock; |
| @@ -167,6 +167,7 @@ static int amdgpu_gtt_mgr_new(struct ttm_resource_manager *man, · 166 unmodified lines | |||
| 167 | return 0; | 167 | return 0; |
| 168 | 168 | ||
| 169 | err_free: | 169 | err_free: |
| 170 | ttm_resource_fini(man, &node->base.base); | ||
| 170 | kfree(node); | 171 | kfree(node); |
| 171 | 172 | ||
| 172 | err_out: | 173 | err_out: |
| @@ -198,6 +199,7 @@ static void amdgpu_gtt_mgr_del(struct ttm_resource_manager *man, · 25 unmodified lines | |||
| 198 | if (!(res->placement & TTM_PL_FLAG_TEMPORARY)) | 199 | if (!(res->placement & TTM_PL_FLAG_TEMPORARY)) |
| 199 | atomic64_sub(res->num_pages, &mgr->used); | 200 | atomic64_sub(res->num_pages, &mgr->used); |
| 200 | 201 | ||
| 202 | ttm_resource_fini(man, res); | ||
| 201 | kfree(node); | 203 | kfree(node); |
| 202 | } | 204 | } |
| 203 | 205 | ||
| @@ -286,7 +288,8 @@ int amdgpu_gtt_mgr_init(struct amdgpu_device *adev, uint64_t gtt_size) · 82 unmodified lines | |||
| 286 | man->use_tt = true; | 288 | man->use_tt = true; |
| 287 | man->func = &amdgpu_gtt_mgr_func; | 289 | man->func = &amdgpu_gtt_mgr_func; |
| 288 | 290 | ||
| 289 | ttm_resource_manager_init(man, gtt_size >> PAGE_SHIFT); | 291 | ttm_resource_manager_init(man, &adev->mman.bdev, |
| 292 | gtt_size >> PAGE_SHIFT); | ||
| 290 | 293 | ||
| 291 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; | 294 | start = AMDGPU_GTT_MAX_TRANSFER_SIZE * AMDGPU_GTT_NUM_TRANSFER_WINDOWS; |
| 292 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; | 295 | size = (adev->gmc.gart_size >> PAGE_SHIFT) - start; |
| @@ -112,7 +112,7 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv, · 111 unmodified lines | |||
| 112 | unsigned count; | 112 | unsigned count; |
| 113 | int r; | 113 | int r; |
| 114 | 114 | ||
| 115 | r = dma_resv_get_fences(resv, NULL, &count, &fences); | 115 | r = dma_resv_get_fences(resv, true, &count, &fences); |
| 116 | if (r) | 116 | if (r) |
| 117 | goto fallback; | 117 | goto fallback; |
| 118 | 118 | ||
| @@ -33,7 +33,7 @@ · 32 unmodified lines | |||
| 33 | #include <drm/drm_crtc.h> | 33 | #include <drm/drm_crtc.h> |
| 34 | #include <drm/drm_edid.h> | 34 | #include <drm/drm_edid.h> |
| 35 | #include <drm/drm_encoder.h> | 35 | #include <drm/drm_encoder.h> |
| 36 | #include <drm/drm_dp_helper.h> | 36 | #include <drm/dp/drm_dp_helper.h> |
| 37 | #include <drm/drm_fixed.h> | 37 | #include <drm/drm_fixed.h> |
| 38 | #include <drm/drm_crtc_helper.h> | 38 | #include <drm/drm_crtc_helper.h> |
| 39 | #include <drm/drm_fb_helper.h> | 39 | #include <drm/drm_fb_helper.h> |
| @@ -44,7 +44,7 @@ · 4 unmodified lines | |||
| 44 | #include <linux/hrtimer.h> | 44 | #include <linux/hrtimer.h> |
| 45 | #include "amdgpu_irq.h" | 45 | #include "amdgpu_irq.h" |
| 46 | 46 | ||
| 47 | #include <drm/drm_dp_mst_helper.h> | 47 | #include <drm/dp/drm_dp_mst_helper.h> |
| 48 | #include "modules/inc/mod_freesync.h" | 48 | #include "modules/inc/mod_freesync.h" |
| 49 | #include "amdgpu_dm_irq_params.h" | 49 | #include "amdgpu_dm_irq_params.h" |
| 50 | 50 | ||
| @@ -95,6 +95,7 @@ static void amdgpu_preempt_mgr_del(struct ttm_resource_manager *man, · 94 unmodified lines | |||
| 95 | struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); | 95 | struct amdgpu_preempt_mgr *mgr = to_preempt_mgr(man); |
| 96 | 96 | ||
| 97 | atomic64_sub(res->num_pages, &mgr->used); | 97 | atomic64_sub(res->num_pages, &mgr->used); |
| 98 | ttm_resource_fini(man, res); | ||
| 98 | kfree(res); | 99 | kfree(res); |
| 99 | } | 100 | } |
| 100 | 101 | ||
| @@ -152,7 +153,7 @@ int amdgpu_preempt_mgr_init(struct amdgpu_device *adev) · 51 unmodified lines | |||
| 152 | man->use_tt = true; | 153 | man->use_tt = true; |
| 153 | man->func = &amdgpu_preempt_mgr_func; | 154 | man->func = &amdgpu_preempt_mgr_func; |
| 154 | 155 | ||
| 155 | ttm_resource_manager_init(man, (1 << 30)); | 156 | ttm_resource_manager_init(man, &adev->mman.bdev, (1 << 30)); |
| 156 | 157 | ||
| 157 | atomic64_set(&mgr->used, 0); | 158 | atomic64_set(&mgr->used, 0); |
| 158 | 159 | ||
| @@ -2087,7 +2087,7 @@ static int amdgpu_mm_vram_table_show(struct seq_file *m, void *unused) · 2086 unmodified lines | |||
| 2087 | TTM_PL_VRAM); | 2087 | TTM_PL_VRAM); |
| 2088 | struct drm_printer p = drm_seq_file_printer(m); | 2088 | struct drm_printer p = drm_seq_file_printer(m); |
| 2089 | 2089 | ||
| 2090 | man->func->debug(man, &p); | 2090 | ttm_resource_manager_debug(man, &p); |
| 2091 | return 0; | 2091 | return 0; |
| 2092 | } | 2092 | } |
| 2093 | 2093 | ||
| @@ -2105,7 +2105,7 @@ static int amdgpu_mm_tt_table_show(struct seq_file *m, void *unused) · 11 unmodified lines | |||
| 2105 | TTM_PL_TT); | 2105 | TTM_PL_TT); |
| 2106 | struct drm_printer p = drm_seq_file_printer(m); | 2106 | struct drm_printer p = drm_seq_file_printer(m); |
| 2107 | 2107 | ||
| 2108 | man->func->debug(man, &p); | 2108 | ttm_resource_manager_debug(man, &p); |
| 2109 | return 0; | 2109 | return 0; |
| 2110 | } | 2110 | } |
| 2111 | 2111 | ||
| @@ -2116,7 +2116,7 @@ static int amdgpu_mm_gds_table_show(struct seq_file *m, void *unused) · 4 unmodified lines | |||
| 2116 | AMDGPU_PL_GDS); | 2116 | AMDGPU_PL_GDS); |
| 2117 | struct drm_printer p = drm_seq_file_printer(m); | 2117 | struct drm_printer p = drm_seq_file_printer(m); |
| 2118 | 2118 | ||
| 2119 | man->func->debug(man, &p); | 2119 | ttm_resource_manager_debug(man, &p); |
| 2120 | return 0; | 2120 | return 0; |
| 2121 | } | 2121 | } |
| 2122 | 2122 | ||
| @@ -2127,7 +2127,7 @@ static int amdgpu_mm_gws_table_show(struct seq_file *m, void *unused) · 4 unmodified lines | |||
| 2127 | AMDGPU_PL_GWS); | 2127 | AMDGPU_PL_GWS); |
| 2128 | struct drm_printer p = drm_seq_file_printer(m); | 2128 | struct drm_printer p = drm_seq_file_printer(m); |
| 2129 | 2129 | ||
| 2130 | man->func->debug(man, &p); | 2130 | ttm_resource_manager_debug(man, &p); |
| 2131 | return 0; | 2131 | return 0; |
| 2132 | } | 2132 | } |
| 2133 | 2133 | ||
| @@ -2138,7 +2138,7 @@ static int amdgpu_mm_oa_table_show(struct seq_file *m, void *unused) · 4 unmodified lines | |||
| 2138 | AMDGPU_PL_OA); | 2138 | AMDGPU_PL_OA); |
| 2139 | struct drm_printer p = drm_seq_file_printer(m); | 2139 | struct drm_printer p = drm_seq_file_printer(m); |
| 2140 | 2140 | ||
| 2141 | man->func->debug(man, &p); | 2141 | ttm_resource_manager_debug(man, &p); |
| 2142 | return 0; | 2142 | return 0; |
| 2143 | } | 2143 | } |
| 2144 | 2144 | ||
| @@ -472,6 +472,7 @@ error_free: · 471 unmodified lines | |||
| 472 | while (i--) | 472 | while (i--) |
| 473 | drm_mm_remove_node(&node->mm_nodes[i]); | 473 | drm_mm_remove_node(&node->mm_nodes[i]); |
| 474 | spin_unlock(&mgr->lock); | 474 | spin_unlock(&mgr->lock); |
| 475 | ttm_resource_fini(man, &node->base); | ||
| 475 | kvfree(node); | 476 | kvfree(node); |
| 476 | 477 | ||
| 477 | error_sub: | 478 | error_sub: |
| @@ -511,6 +512,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, · 33 unmodified lines | |||
| 511 | atomic64_sub(usage, &mgr->usage); | 512 | atomic64_sub(usage, &mgr->usage); |
| 512 | atomic64_sub(vis_usage, &mgr->vis_usage); | 513 | atomic64_sub(vis_usage, &mgr->vis_usage); |
| 513 | 514 | ||
| 515 | ttm_resource_fini(man, res); | ||
| 514 | kvfree(node); | 516 | kvfree(node); |
| 515 | } | 517 | } |
| 516 | 518 | ||
| @@ -689,7 +691,8 @@ int amdgpu_vram_mgr_init(struct amdgpu_device *adev) · 172 unmodified lines | |||
| 689 | struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; | 691 | struct amdgpu_vram_mgr *mgr = &adev->mman.vram_mgr; |
| 690 | struct ttm_resource_manager *man = &mgr->manager; | 692 | struct ttm_resource_manager *man = &mgr->manager; |
| 691 | 693 | ||
| 692 | ttm_resource_manager_init(man, adev->gmc.real_vram_size >> PAGE_SHIFT); | 694 | ttm_resource_manager_init(man, &adev->mman.bdev, |
| 695 | adev->gmc.real_vram_size >> PAGE_SHIFT); | ||
| 693 | 696 | ||
| 694 | man->func = &amdgpu_vram_mgr_func; | 697 | man->func = &amdgpu_vram_mgr_func; |
| 695 | 698 | ||
| @@ -34,7 +34,7 @@ · 33 unmodified lines | |||
| 34 | #include "atombios_dp.h" | 34 | #include "atombios_dp.h" |
| 35 | #include "amdgpu_connectors.h" | 35 | #include "amdgpu_connectors.h" |
| 36 | #include "amdgpu_atombios.h" | 36 | #include "amdgpu_atombios.h" |
| 37 | #include <drm/drm_dp_helper.h> | 37 | #include <drm/dp/drm_dp_helper.h> |
| 38 | 38 | ||
| 39 | /* move these to drm_dp_helper.c/h */ | 39 | /* move these to drm_dp_helper.c/h */ |
| 40 | #define DP_LINK_CONFIGURATION_SIZE 9 | 40 | #define DP_LINK_CONFIGURATION_SIZE 9 |
| @@ -76,7 +76,7 @@ · 75 unmodified lines | |||
| 76 | #include <drm/drm_atomic.h> | 76 | #include <drm/drm_atomic.h> |
| 77 | #include <drm/drm_atomic_uapi.h> | 77 | #include <drm/drm_atomic_uapi.h> |
| 78 | #include <drm/drm_atomic_helper.h> | 78 | #include <drm/drm_atomic_helper.h> |
| 79 | #include <drm/drm_dp_mst_helper.h> | 79 | #include <drm/dp/drm_dp_mst_helper.h> |
| 80 | #include <drm/drm_fb_helper.h> | 80 | #include <drm/drm_fb_helper.h> |
| 81 | #include <drm/drm_fourcc.h> | 81 | #include <drm/drm_fourcc.h> |
| 82 | #include <drm/drm_edid.h> | 82 | #include <drm/drm_edid.h> |
| @@ -5856,7 +5856,7 @@ static void fill_stream_properties_from_drm_display_mode( · 5773 unmodified lines | |||
| 5856 | else if (drm_mode_is_420_also(info, mode_in) | 5856 | else if (drm_mode_is_420_also(info, mode_in) |
| 5857 | && aconnector->force_yuv420_output) | 5857 | && aconnector->force_yuv420_output) |
| 5858 | timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; | 5858 | timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420; |
| 5859 | else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444) | 5859 | else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444) |
| 5860 | && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) | 5860 | && stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) |
| 5861 | timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; | 5861 | timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444; |
| 5862 | else | 5862 | else |
| @@ -29,7 +29,7 @@ · 28 unmodified lines | |||
| 29 | #include <drm/drm_atomic.h> | 29 | #include <drm/drm_atomic.h> |
| 30 | #include <drm/drm_connector.h> | 30 | #include <drm/drm_connector.h> |
| 31 | #include <drm/drm_crtc.h> | 31 | #include <drm/drm_crtc.h> |
| 32 | #include <drm/drm_dp_mst_helper.h> | 32 | #include <drm/dp/drm_dp_mst_helper.h> |
| 33 | #include <drm/drm_plane.h> | 33 | #include <drm/drm_plane.h> |
| 34 | 34 | ||
| 35 | /* | 35 | /* |
| @@ -25,8 +25,8 @@ · 24 unmodified lines | |||
| 25 | 25 | ||
| 26 | #include <drm/drm_atomic.h> | 26 | #include <drm/drm_atomic.h> |
| 27 | #include <drm/drm_atomic_helper.h> | 27 | #include <drm/drm_atomic_helper.h> |
| 28 | #include <drm/drm_dp_mst_helper.h> | 28 | #include <drm/dp/drm_dp_mst_helper.h> |
| 29 | #include <drm/drm_dp_helper.h> | 29 | #include <drm/dp/drm_dp_helper.h> |
| 30 | #include "dm_services.h" | 30 | #include "dm_services.h" |
| 31 | #include "amdgpu.h" | 31 | #include "amdgpu.h" |
| 32 | #include "amdgpu_dm.h" | 32 | #include "amdgpu_dm.h" |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | |||
| 27 | #include <dc_link.h> | 27 | #include <dc_link.h> |
| 28 | #include <inc/link_hwss.h> | 28 | #include <inc/link_hwss.h> |
| 29 | #include <inc/link_dpcd.h> | 29 | #include <inc/link_dpcd.h> |
| 30 | #include "drm/drm_dp_helper.h" | 30 | #include <drm/dp/drm_dp_helper.h> |
| 31 | #include <dc_dp_types.h> | 31 | #include <dc_dp_types.h> |
| 32 | #include "dm_helpers.h" | 32 | #include "dm_helpers.h" |
| 33 | 33 | ||
| @@ -25,7 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <drm/drm_dsc.h> | 25 | #include <drm/drm_dsc.h> |
| 26 | #include "dc_hw_types.h" | 26 | #include "dc_hw_types.h" |
| 27 | #include "dsc.h" | 27 | #include "dsc.h" |
| 28 | #include <drm/drm_dp_helper.h> | 28 | #include <drm/dp/drm_dp_helper.h> |
| 29 | #include "dc.h" | 29 | #include "dc.h" |
| 30 | #include "rc_calc.h" | 30 | #include "rc_calc.h" |
| 31 | #include "fixed31_32.h" | 31 | #include "fixed31_32.h" |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | |||
| 36 | #include <asm/byteorder.h> | 36 | #include <asm/byteorder.h> |
| 37 | 37 | ||
| 38 | #include <drm/drm_print.h> | 38 | #include <drm/drm_print.h> |
| 39 | #include <drm/drm_dp_helper.h> | 39 | #include <drm/dp/drm_dp_helper.h> |
| 40 | 40 | ||
| 41 | #include "cgs_common.h" | 41 | #include "cgs_common.h" |
| 42 | 42 | ||
| @@ -26,7 +26,7 @@ · 25 unmodified lines | |||
| 26 | #ifndef __DAL_DPCD_DEFS_H__ | 26 | #ifndef __DAL_DPCD_DEFS_H__ |
| 27 | #define __DAL_DPCD_DEFS_H__ | 27 | #define __DAL_DPCD_DEFS_H__ |
| 28 | 28 | ||
| 29 | #include <drm/drm_dp_helper.h> | 29 | #include <drm/dp/drm_dp_helper.h> |
| 30 | #ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h | 30 | #ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h |
| 31 | #define DP_SINK_HW_REVISION_START 0x409 | 31 | #define DP_SINK_HW_REVISION_START 0x409 |
| 32 | #endif | 32 | #endif |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include "hdcp_log.h" | 30 | #include "hdcp_log.h" |
| 31 | 31 | ||
| 32 | #include <drm/drm_hdcp.h> | 32 | #include <drm/drm_hdcp.h> |
| 33 | #include <drm/drm_dp_helper.h> | 33 | #include <drm/dp/drm_dp_helper.h> |
| 34 | 34 | ||
| 35 | enum mod_hdcp_trans_input_result { | 35 | enum mod_hdcp_trans_input_result { |
| 36 | UNKNOWN = 0, | 36 | UNKNOWN = 0, |
| @@ -1078,11 +1078,11 @@ static void d71_improc_update(struct komeda_component *c, · 1077 unmodified lines | |||
| 1078 | mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; | 1078 | mask |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; |
| 1079 | 1079 | ||
| 1080 | /* config color format */ | 1080 | /* config color format */ |
| 1081 | if (st->color_format == DRM_COLOR_FORMAT_YCRCB420) | 1081 | if (st->color_format == DRM_COLOR_FORMAT_YCBCR420) |
| 1082 | ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; | 1082 | ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422 | IPS_CTRL_CHD420; |
| 1083 | else if (st->color_format == DRM_COLOR_FORMAT_YCRCB422) | 1083 | else if (st->color_format == DRM_COLOR_FORMAT_YCBCR422) |
| 1084 | ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; | 1084 | ctrl |= IPS_CTRL_YUV | IPS_CTRL_CHD422; |
| 1085 | else if (st->color_format == DRM_COLOR_FORMAT_YCRCB444) | 1085 | else if (st->color_format == DRM_COLOR_FORMAT_YCBCR444) |
| 1086 | ctrl |= IPS_CTRL_YUV; | 1086 | ctrl |= IPS_CTRL_YUV; |
| 1087 | 1087 | ||
| 1088 | malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); | 1088 | malidp_write32_mask(reg, BLK_CONTROL, mask, ctrl); |
| @@ -1144,11 +1144,11 @@ static int d71_improc_init(struct d71_dev *d71, · 55 unmodified lines | |||
| 1144 | improc = to_improc(c); | 1144 | improc = to_improc(c); |
| 1145 | improc->supported_color_depths = BIT(8) | BIT(10); | 1145 | improc->supported_color_depths = BIT(8) | BIT(10); |
| 1146 | improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | | 1146 | improc->supported_color_formats = DRM_COLOR_FORMAT_RGB444 | |
| 1147 | DRM_COLOR_FORMAT_YCRCB444 | | 1147 | DRM_COLOR_FORMAT_YCBCR444 | |
| 1148 | DRM_COLOR_FORMAT_YCRCB422; | 1148 | DRM_COLOR_FORMAT_YCBCR422; |
| 1149 | value = malidp_read32(reg, BLK_INFO); | 1149 | value = malidp_read32(reg, BLK_INFO); |
| 1150 | if (value & IPS_INFO_CHD420) | 1150 | if (value & IPS_INFO_CHD420) |
| 1151 | improc->supported_color_formats |= DRM_COLOR_FORMAT_YCRCB420; | 1151 | improc->supported_color_formats |= DRM_COLOR_FORMAT_YCBCR420; |
| 1152 | 1152 | ||
| 1153 | improc->supports_csc = true; | 1153 | improc->supports_csc = true; |
| 1154 | improc->supports_gamma = true; | 1154 | improc->supports_gamma = true; |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/component.h> | 10 | #include <linux/component.h> |
| 11 | #include <linux/pm_runtime.h> | 11 | #include <linux/pm_runtime.h> |
| 12 | #include <drm/drm_module.h> | ||
| 12 | #include <drm/drm_of.h> | 13 | #include <drm/drm_of.h> |
| 13 | #include "komeda_dev.h" | 14 | #include "komeda_dev.h" |
| 14 | #include "komeda_kms.h" | 15 | #include "komeda_kms.h" |
| @@ -198,7 +199,7 @@ static struct platform_driver komeda_platform_driver = { · 183 unmodified lines | |||
| 198 | }, | 199 | }, |
| 199 | }; | 200 | }; |
| 200 | 201 | ||
| 201 | module_platform_driver(komeda_platform_driver); | 202 | drm_module_platform_driver(komeda_platform_driver); |
| 202 | 203 | ||
| 203 | MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); | 204 | MODULE_AUTHOR("James.Qian.Wang <james.qian.wang@arm.com>"); |
| 204 | MODULE_DESCRIPTION("Komeda KMS driver"); | 205 | MODULE_DESCRIPTION("Komeda KMS driver"); |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | |||
| 30 | #include <drm/drm_gem_cma_helper.h> | 30 | #include <drm/drm_gem_cma_helper.h> |
| 31 | #include <drm/drm_gem_framebuffer_helper.h> | 31 | #include <drm/drm_gem_framebuffer_helper.h> |
| 32 | #include <drm/drm_modeset_helper.h> | 32 | #include <drm/drm_modeset_helper.h> |
| 33 | #include <drm/drm_module.h> | ||
| 33 | #include <drm/drm_of.h> | 34 | #include <drm/drm_of.h> |
| 34 | #include <drm/drm_probe_helper.h> | 35 | #include <drm/drm_probe_helper.h> |
| 35 | #include <drm/drm_vblank.h> | 36 | #include <drm/drm_vblank.h> |
| @@ -434,7 +435,7 @@ static struct platform_driver hdlcd_platform_driver = { · 398 unmodified lines | |||
| 434 | }, | 435 | }, |
| 435 | }; | 436 | }; |
| 436 | 437 | ||
| 437 | module_platform_driver(hdlcd_platform_driver); | 438 | drm_module_platform_driver(hdlcd_platform_driver); |
| 438 | 439 | ||
| 439 | MODULE_AUTHOR("Liviu Dudau"); | 440 | MODULE_AUTHOR("Liviu Dudau"); |
| 440 | MODULE_DESCRIPTION("ARM HDLCD DRM driver"); | 441 | MODULE_DESCRIPTION("ARM HDLCD DRM driver"); |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <drm/drm_gem_cma_helper.h> | 25 | #include <drm/drm_gem_cma_helper.h> |
| 26 | #include <drm/drm_gem_framebuffer_helper.h> | 26 | #include <drm/drm_gem_framebuffer_helper.h> |
| 27 | #include <drm/drm_modeset_helper.h> | 27 | #include <drm/drm_modeset_helper.h> |
| 28 | #include <drm/drm_module.h> | ||
| 28 | #include <drm/drm_of.h> | 29 | #include <drm/drm_of.h> |
| 29 | #include <drm/drm_probe_helper.h> | 30 | #include <drm/drm_probe_helper.h> |
| 30 | #include <drm/drm_vblank.h> | 31 | #include <drm/drm_vblank.h> |
| @@ -1008,7 +1009,7 @@ static struct platform_driver malidp_platform_driver = { · 977 unmodified lines | |||
| 1008 | }, | 1009 | }, |
| 1009 | }; | 1010 | }; |
| 1010 | 1011 | ||
| 1011 | module_platform_driver(malidp_platform_driver); | 1012 | drm_module_platform_driver(malidp_platform_driver); |
| 1012 | 1013 | ||
| 1013 | MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); | 1014 | MODULE_AUTHOR("Liviu Dudau <Liviu.Dudau@arm.com>"); |
| 1014 | MODULE_DESCRIPTION("ARM Mali DP DRM driver"); | 1015 | MODULE_DESCRIPTION("ARM Mali DP DRM driver"); |
| @@ -34,6 +34,7 @@ · 33 unmodified lines | |||
| 34 | #include <drm/drm_crtc_helper.h> | 34 | #include <drm/drm_crtc_helper.h> |
| 35 | #include <drm/drm_drv.h> | 35 | #include <drm/drm_drv.h> |
| 36 | #include <drm/drm_gem_vram_helper.h> | 36 | #include <drm/drm_gem_vram_helper.h> |
| 37 | #include <drm/drm_module.h> | ||
| 37 | #include <drm/drm_probe_helper.h> | 38 | #include <drm/drm_probe_helper.h> |
| 38 | 39 | ||
| 39 | #include "ast_drv.h" | 40 | #include "ast_drv.h" |
| @@ -230,22 +231,7 @@ static struct pci_driver ast_pci_driver = { · 190 unmodified lines | |||
| 230 | .driver.pm = &ast_pm_ops, | 231 | .driver.pm = &ast_pm_ops, |
| 231 | }; | 232 | }; |
| 232 | 233 | ||
| 233 | static int __init ast_init(void) | 234 | drm_module_pci_driver_if_modeset(ast_pci_driver, ast_modeset); |
| 234 | { | ||
| 235 | if (drm_firmware_drivers_only() && ast_modeset == -1) | ||
| 236 | return -EINVAL; | ||
| 237 | |||
| 238 | if (ast_modeset == 0) | ||
| 239 | return -EINVAL; | ||
| 240 | return pci_register_driver(&ast_pci_driver); | ||
| 241 | } | ||
| 242 | static void __exit ast_exit(void) | ||
| 243 | { | ||
| 244 | pci_unregister_driver(&ast_pci_driver); | ||
| 245 | } | ||
| 246 | |||
| 247 | module_init(ast_init); | ||
| 248 | module_exit(ast_exit); | ||
| 249 | 235 | ||
| 250 | MODULE_AUTHOR(DRIVER_AUTHOR); | 236 | MODULE_AUTHOR(DRIVER_AUTHOR); |
| 251 | MODULE_DESCRIPTION(DRIVER_DESC); | 237 | MODULE_DESCRIPTION(DRIVER_DESC); |
| @@ -209,6 +209,8 @@ static int ast_detect_chip(struct drm_device *dev, bool *need_post) · 208 unmodified lines | |||
| 209 | if (ast->chip == AST2500 && | 209 | if (ast->chip == AST2500 && |
| 210 | scu_rev == 0x100) /* ast2510 */ | 210 | scu_rev == 0x100) /* ast2510 */ |
| 211 | ast->support_wide_screen = true; | 211 | ast->support_wide_screen = true; |
| 212 | if (ast->chip == AST2600) /* ast2600 */ | ||
| 213 | ast->support_wide_screen = true; | ||
| 212 | } | 214 | } |
| 213 | break; | 215 | break; |
| 214 | } | 216 | } |
| @@ -471,7 +471,10 @@ static void ast_set_color_reg(struct ast_private *ast, · 470 unmodified lines | |||
| 471 | static void ast_set_crtthd_reg(struct ast_private *ast) | 471 | static void ast_set_crtthd_reg(struct ast_private *ast) |
| 472 | { | 472 | { |
| 473 | /* Set Threshold */ | 473 | /* Set Threshold */ |
| 474 | if (ast->chip == AST2300 || ast->chip == AST2400 || | 474 | if (ast->chip == AST2600) { |
| 475 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0xe0); | ||
| 476 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0xa0); | ||
| 477 | } else if (ast->chip == AST2300 || ast->chip == AST2400 || | ||
| 475 | ast->chip == AST2500) { | 478 | ast->chip == AST2500) { |
| 476 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); | 479 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa7, 0x78); |
| 477 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); | 480 | ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xa6, 0x60); |
| @@ -30,6 +30,7 @@ config DRM_CDNS_DSI · 29 unmodified lines | |||
| 30 | config DRM_CHIPONE_ICN6211 | 30 | config DRM_CHIPONE_ICN6211 |
| 31 | tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" | 31 | tristate "Chipone ICN6211 MIPI-DSI/RGB Converter bridge" |
| 32 | depends on OF | 32 | depends on OF |
| 33 | depends on DRM_KMS_HELPER | ||
| 33 | select DRM_MIPI_DSI | 34 | select DRM_MIPI_DSI |
| 34 | select DRM_PANEL_BRIDGE | 35 | select DRM_PANEL_BRIDGE |
| 35 | help | 36 | help |
| @@ -183,6 +184,7 @@ config DRM_PARADE_PS8640 · 147 unmodified lines | |||
| 183 | tristate "Parade PS8640 MIPI DSI to eDP Converter" | 184 | tristate "Parade PS8640 MIPI DSI to eDP Converter" |
| 184 | depends on OF | 185 | depends on OF |
| 185 | select DRM_DP_AUX_BUS | 186 | select DRM_DP_AUX_BUS |
| 187 | select DRM_DP_HELPER | ||
| 186 | select DRM_KMS_HELPER | 188 | select DRM_KMS_HELPER |
| 187 | select DRM_MIPI_DSI | 189 | select DRM_MIPI_DSI |
| 188 | select DRM_PANEL | 190 | select DRM_PANEL |
| @@ -253,6 +255,7 @@ config DRM_TOSHIBA_TC358764 · 64 unmodified lines | |||
| 253 | config DRM_TOSHIBA_TC358767 | 255 | config DRM_TOSHIBA_TC358767 |
| 254 | tristate "Toshiba TC358767 eDP bridge" | 256 | tristate "Toshiba TC358767 eDP bridge" |
| 255 | depends on OF | 257 | depends on OF |
| 258 | select DRM_DP_HELPER | ||
| 256 | select DRM_KMS_HELPER | 259 | select DRM_KMS_HELPER |
| 257 | select REGMAP_I2C | 260 | select REGMAP_I2C |
| 258 | select DRM_PANEL | 261 | select DRM_PANEL |
| @@ -272,6 +275,7 @@ config DRM_TOSHIBA_TC358768 · 13 unmodified lines | |||
| 272 | config DRM_TOSHIBA_TC358775 | 275 | config DRM_TOSHIBA_TC358775 |
| 273 | tristate "Toshiba TC358775 DSI/LVDS bridge" | 276 | tristate "Toshiba TC358775 DSI/LVDS bridge" |
| 274 | depends on OF | 277 | depends on OF |
| 278 | select DRM_DP_HELPER | ||
| 275 | select DRM_KMS_HELPER | 279 | select DRM_KMS_HELPER |
| 276 | select REGMAP_I2C | 280 | select REGMAP_I2C |
| 277 | select DRM_PANEL | 281 | select DRM_PANEL |
| @@ -299,6 +303,7 @@ config DRM_TI_SN65DSI83 · 21 unmodified lines | |||
| 299 | config DRM_TI_SN65DSI86 | 303 | config DRM_TI_SN65DSI86 |
| 300 | tristate "TI SN65DSI86 DSI to eDP bridge" | 304 | tristate "TI SN65DSI86 DSI to eDP bridge" |
| 301 | depends on OF | 305 | depends on OF |
| 306 | select DRM_DP_HELPER | ||
| 302 | select DRM_KMS_HELPER | 307 | select DRM_KMS_HELPER |
| 303 | select REGMAP_I2C | 308 | select REGMAP_I2C |
| 304 | select DRM_PANEL | 309 | select DRM_PANEL |
| @@ -169,6 +169,7 @@ · 168 unmodified lines | |||
| 169 | #define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) | 169 | #define ADV7511_PACKET_ENABLE_SPARE2 BIT(1) |
| 170 | #define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) | 170 | #define ADV7511_PACKET_ENABLE_SPARE1 BIT(0) |
| 171 | 171 | ||
| 172 | #define ADV7535_REG_POWER2_HPD_OVERRIDE BIT(6) | ||
| 172 | #define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 | 173 | #define ADV7511_REG_POWER2_HPD_SRC_MASK 0xc0 |
| 173 | #define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 | 174 | #define ADV7511_REG_POWER2_HPD_SRC_BOTH 0x00 |
| 174 | #define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 | 175 | #define ADV7511_REG_POWER2_HPD_SRC_HPD 0x40 |
| @@ -223,7 +223,7 @@ static void adv7511_set_config_csc(struct adv7511 *adv7511, · 222 unmodified lines | |||
| 223 | config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; | 223 | config.csc_coefficents = adv7511_csc_ycbcr_to_rgb; |
| 224 | 224 | ||
| 225 | if ((connector->display_info.color_formats & | 225 | if ((connector->display_info.color_formats & |
| 226 | DRM_COLOR_FORMAT_YCRCB422) && | 226 | DRM_COLOR_FORMAT_YCBCR422) && |
| 227 | config.hdmi_mode) { | 227 | config.hdmi_mode) { |
| 228 | config.csc_enable = false; | 228 | config.csc_enable = false; |
| 229 | config.avi_infoframe.colorspace = | 229 | config.avi_infoframe.colorspace = |
| @@ -351,11 +351,17 @@ static void __adv7511_power_on(struct adv7511 *adv7511) · 121 unmodified lines | |||
| 351 | * from standby or are enabled. When the HPD goes low the adv7511 is | 351 | * from standby or are enabled. When the HPD goes low the adv7511 is |
| 352 | * reset and the outputs are disabled which might cause the monitor to | 352 | * reset and the outputs are disabled which might cause the monitor to |
| 353 | * go to standby again. To avoid this we ignore the HPD pin for the | 353 | * go to standby again. To avoid this we ignore the HPD pin for the |
| 354 | * first few seconds after enabling the output. | 354 | * first few seconds after enabling the output. On the other hand |
| 355 | * adv7535 require to enable HPD Override bit for proper HPD. | ||
| 355 | */ | 356 | */ |
| 356 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | 357 | if (adv7511->type == ADV7535) |
| 357 | ADV7511_REG_POWER2_HPD_SRC_MASK, | 358 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, |
| 358 | ADV7511_REG_POWER2_HPD_SRC_NONE); | 359 | ADV7535_REG_POWER2_HPD_OVERRIDE, |
| 360 | ADV7535_REG_POWER2_HPD_OVERRIDE); | ||
| 361 | else | ||
| 362 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||
| 363 | ADV7511_REG_POWER2_HPD_SRC_MASK, | ||
| 364 | ADV7511_REG_POWER2_HPD_SRC_NONE); | ||
| 359 | } | 365 | } |
| 360 | 366 | ||
| 361 | static void adv7511_power_on(struct adv7511 *adv7511) | 367 | static void adv7511_power_on(struct adv7511 *adv7511) |
| @@ -375,6 +381,10 @@ static void adv7511_power_on(struct adv7511 *adv7511) · 13 unmodified lines | |||
| 375 | static void __adv7511_power_off(struct adv7511 *adv7511) | 381 | static void __adv7511_power_off(struct adv7511 *adv7511) |
| 376 | { | 382 | { |
| 377 | /* TODO: setup additional power down modes */ | 383 | /* TODO: setup additional power down modes */ |
| 384 | if (adv7511->type == ADV7535) | ||
| 385 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||
| 386 | ADV7535_REG_POWER2_HPD_OVERRIDE, 0); | ||
| 387 | |||
| 378 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, | 388 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER, |
| 379 | ADV7511_POWER_POWER_DOWN, | 389 | ADV7511_POWER_POWER_DOWN, |
| 380 | ADV7511_POWER_POWER_DOWN); | 390 | ADV7511_POWER_POWER_DOWN); |
| @@ -672,9 +682,14 @@ adv7511_detect(struct adv7511 *adv7511, struct drm_connector *connector) · 291 unmodified lines | |||
| 672 | status = connector_status_disconnected; | 682 | status = connector_status_disconnected; |
| 673 | } else { | 683 | } else { |
| 674 | /* Renable HPD sensing */ | 684 | /* Renable HPD sensing */ |
| 675 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | 685 | if (adv7511->type == ADV7535) |
| 676 | ADV7511_REG_POWER2_HPD_SRC_MASK, | 686 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, |
| 677 | ADV7511_REG_POWER2_HPD_SRC_BOTH); | 687 | ADV7535_REG_POWER2_HPD_OVERRIDE, |
| 688 | ADV7535_REG_POWER2_HPD_OVERRIDE); | ||
| 689 | else | ||
| 690 | regmap_update_bits(adv7511->regmap, ADV7511_REG_POWER2, | ||
| 691 | ADV7511_REG_POWER2_HPD_SRC_MASK, | ||
| 692 | ADV7511_REG_POWER2_HPD_SRC_BOTH); | ||
| 678 | } | 693 | } |
| 679 | 694 | ||
| 680 | adv7511->status = status; | 695 | adv7511->status = status; |
| @@ -29,7 +29,7 @@ static void adv7511_dsi_config_timing_gen(struct adv7511 *adv) · 28 unmodified lines | |||
| 29 | struct mipi_dsi_device *dsi = adv->dsi; | 29 | struct mipi_dsi_device *dsi = adv->dsi; |
| 30 | struct drm_display_mode *mode = &adv->curr_mode; | 30 | struct drm_display_mode *mode = &adv->curr_mode; |
| 31 | unsigned int hsw, hfp, hbp, vsw, vfp, vbp; | 31 | unsigned int hsw, hfp, hbp, vsw, vfp, vbp; |
| 32 | u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ | 32 | static const u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ |
| 33 | 33 | ||
| 34 | hsw = mode->hsync_end - mode->hsync_start; | 34 | hsw = mode->hsync_end - mode->hsync_start; |
| 35 | hfp = mode->hsync_start - mode->hdisplay; | 35 | hfp = mode->hsync_start - mode->hdisplay; |
| @@ -3,6 +3,7 @@ config DRM_ANALOGIX_ANX6345 · 2 unmodified lines | |||
| 3 | tristate "Analogix ANX6345 bridge" | 3 | tristate "Analogix ANX6345 bridge" |
| 4 | depends on OF | 4 | depends on OF |
| 5 | select DRM_ANALOGIX_DP | 5 | select DRM_ANALOGIX_DP |
| 6 | select DRM_DP_HELPER | ||
| 6 | select DRM_KMS_HELPER | 7 | select DRM_KMS_HELPER |
| 7 | select REGMAP_I2C | 8 | select REGMAP_I2C |
| 8 | help | 9 | help |
| @@ -14,6 +15,7 @@ config DRM_ANALOGIX_ANX6345 · 5 unmodified lines | |||
| 14 | config DRM_ANALOGIX_ANX78XX | 15 | config DRM_ANALOGIX_ANX78XX |
| 15 | tristate "Analogix ANX78XX bridge" | 16 | tristate "Analogix ANX78XX bridge" |
| 16 | select DRM_ANALOGIX_DP | 17 | select DRM_ANALOGIX_DP |
| 18 | select DRM_DP_HELPER | ||
| 17 | select DRM_KMS_HELPER | 19 | select DRM_KMS_HELPER |
| 18 | select REGMAP_I2C | 20 | select REGMAP_I2C |
| 19 | help | 21 | help |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | #include <drm/drm_bridge.h> | 22 | #include <drm/drm_bridge.h> |
| 23 | #include <drm/drm_crtc.h> | 23 | #include <drm/drm_crtc.h> |
| 24 | #include <drm/drm_crtc_helper.h> | 24 | #include <drm/drm_crtc_helper.h> |
| 25 | #include <drm/drm_dp_helper.h> | 25 | #include <drm/dp/drm_dp_helper.h> |
| 26 | #include <drm/drm_edid.h> | 26 | #include <drm/drm_edid.h> |
| 27 | #include <drm/drm_of.h> | 27 | #include <drm/drm_of.h> |
| 28 | #include <drm/drm_panel.h> | 28 | #include <drm/drm_panel.h> |
| @@ -21,7 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include <drm/drm_atomic_helper.h> | 21 | #include <drm/drm_atomic_helper.h> |
| 22 | #include <drm/drm_bridge.h> | 22 | #include <drm/drm_bridge.h> |
| 23 | #include <drm/drm_crtc.h> | 23 | #include <drm/drm_crtc.h> |
| 24 | #include <drm/drm_dp_helper.h> | 24 | #include <drm/dp/drm_dp_helper.h> |
| 25 | #include <drm/drm_edid.h> | 25 | #include <drm/drm_edid.h> |
| 26 | #include <drm/drm_print.h> | 26 | #include <drm/drm_print.h> |
| 27 | #include <drm/drm_probe_helper.h> | 27 | #include <drm/drm_probe_helper.h> |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | |||
| 8 | #include <linux/regmap.h> | 8 | #include <linux/regmap.h> |
| 9 | 9 | ||
| 10 | #include <drm/drm.h> | 10 | #include <drm/drm.h> |
| 11 | #include <drm/drm_dp_helper.h> | 11 | #include <drm/dp/drm_dp_helper.h> |
| 12 | #include <drm/drm_print.h> | 12 | #include <drm/drm_print.h> |
| 13 | 13 | ||
| 14 | #include "analogix-i2c-dptx.h" | 14 | #include "analogix-i2c-dptx.h" |
| @@ -1537,9 +1537,9 @@ static void analogix_dp_bridge_mode_set(struct drm_bridge *bridge, · 1536 unmodified lines | |||
| 1537 | video->color_depth = COLOR_8; | 1537 | video->color_depth = COLOR_8; |
| 1538 | break; | 1538 | break; |
| 1539 | } | 1539 | } |
| 1540 | if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | 1540 | if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR444) |
| 1541 | video->color_space = COLOR_YCBCR444; | 1541 | video->color_space = COLOR_YCBCR444; |
| 1542 | else if (display_info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | 1542 | else if (display_info->color_formats & DRM_COLOR_FORMAT_YCBCR422) |
| 1543 | video->color_space = COLOR_YCBCR422; | 1543 | video->color_space = COLOR_YCBCR422; |
| 1544 | else | 1544 | else |
| 1545 | video->color_space = COLOR_RGB; | 1545 | video->color_space = COLOR_RGB; |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #define _ANALOGIX_DP_CORE_H | 10 | #define _ANALOGIX_DP_CORE_H |
| 11 | 11 | ||
| 12 | #include <drm/drm_crtc.h> | 12 | #include <drm/drm_crtc.h> |
| 13 | #include <drm/drm_dp_helper.h> | 13 | #include <drm/dp/drm_dp_helper.h> |
| 14 | 14 | ||
| 15 | #define DP_TIMEOUT_LOOP_COUNT 100 | 15 | #define DP_TIMEOUT_LOOP_COUNT 100 |
| 16 | #define MAX_CR_LOOP 5 | 16 | #define MAX_CR_LOOP 5 |
| @@ -24,8 +24,9 @@ · 23 unmodified lines | |||
| 24 | #include <drm/drm_atomic_helper.h> | 24 | #include <drm/drm_atomic_helper.h> |
| 25 | #include <drm/drm_bridge.h> | 25 | #include <drm/drm_bridge.h> |
| 26 | #include <drm/drm_crtc_helper.h> | 26 | #include <drm/drm_crtc_helper.h> |
| 27 | #include <drm/drm_dp_helper.h> | 27 | #include <drm/dp/drm_dp_helper.h> |
| 28 | #include <drm/drm_edid.h> | 28 | #include <drm/drm_edid.h> |
| 29 | #include <drm/drm_hdcp.h> | ||
| 29 | #include <drm/drm_mipi_dsi.h> | 30 | #include <drm/drm_mipi_dsi.h> |
| 30 | #include <drm/drm_of.h> | 31 | #include <drm/drm_of.h> |
| 31 | #include <drm/drm_panel.h> | 32 | #include <drm/drm_panel.h> |
| @@ -213,6 +214,65 @@ static int wait_aux_op_finish(struct anx7625_data *ctx) · 181 unmodified lines | |||
| 213 | return 0; | 214 | return 0; |
| 214 | } | 215 | } |
| 215 | 216 | ||
| 217 | static int anx7625_aux_dpcd_read(struct anx7625_data *ctx, | ||
| 218 | u32 address, u8 len, u8 *buf) | ||
| 219 | { | ||
| 220 | struct device *dev = &ctx->client->dev; | ||
| 221 | int ret; | ||
| 222 | u8 addrh, addrm, addrl; | ||
| 223 | u8 cmd; | ||
| 224 | |||
| 225 | if (len > MAX_DPCD_BUFFER_SIZE) { | ||
| 226 | dev_err(dev, "exceed aux buffer len.\n"); | ||
| 227 | return -EINVAL; | ||
| 228 | } | ||
| 229 | |||
| 230 | addrl = address & 0xFF; | ||
| 231 | addrm = (address >> 8) & 0xFF; | ||
| 232 | addrh = (address >> 16) & 0xFF; | ||
| 233 | |||
| 234 | cmd = DPCD_CMD(len, DPCD_READ); | ||
| 235 | cmd = ((len - 1) << 4) | 0x09; | ||
| 236 | |||
| 237 | /* Set command and length */ | ||
| 238 | ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 239 | AP_AUX_COMMAND, cmd); | ||
| 240 | |||
| 241 | /* Set aux access address */ | ||
| 242 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 243 | AP_AUX_ADDR_7_0, addrl); | ||
| 244 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 245 | AP_AUX_ADDR_15_8, addrm); | ||
| 246 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 247 | AP_AUX_ADDR_19_16, addrh); | ||
| 248 | |||
| 249 | /* Enable aux access */ | ||
| 250 | ret |= anx7625_write_or(ctx, ctx->i2c.rx_p0_client, | ||
| 251 | AP_AUX_CTRL_STATUS, AP_AUX_CTRL_OP_EN); | ||
| 252 | |||
| 253 | if (ret < 0) { | ||
| 254 | dev_err(dev, "cannot access aux related register.\n"); | ||
| 255 | return -EIO; | ||
| 256 | } | ||
| 257 | |||
| 258 | usleep_range(2000, 2100); | ||
| 259 | |||
| 260 | ret = wait_aux_op_finish(ctx); | ||
| 261 | if (ret) { | ||
| 262 | dev_err(dev, "aux IO error: wait aux op finish.\n"); | ||
| 263 | return ret; | ||
| 264 | } | ||
| 265 | |||
| 266 | ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, | ||
| 267 | AP_AUX_BUFF_START, len, buf); | ||
| 268 | if (ret < 0) { | ||
| 269 | dev_err(dev, "read dpcd register failed\n"); | ||
| 270 | return -EIO; | ||
| 271 | } | ||
| 272 | |||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 216 | static int anx7625_video_mute_control(struct anx7625_data *ctx, | 276 | static int anx7625_video_mute_control(struct anx7625_data *ctx, |
| 217 | u8 status) | 277 | u8 status) |
| 218 | { | 278 | { |
| @@ -669,6 +729,165 @@ static int anx7625_dpi_config(struct anx7625_data *ctx) · 450 unmodified lines | |||
| 669 | return ret; | 729 | return ret; |
| 670 | } | 730 | } |
| 671 | 731 | ||
| 732 | static int anx7625_read_flash_status(struct anx7625_data *ctx) | ||
| 733 | { | ||
| 734 | return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, R_RAM_CTRL); | ||
| 735 | } | ||
| 736 | |||
| 737 | static int anx7625_hdcp_key_probe(struct anx7625_data *ctx) | ||
| 738 | { | ||
| 739 | int ret, val; | ||
| 740 | struct device *dev = &ctx->client->dev; | ||
| 741 | u8 ident[FLASH_BUF_LEN]; | ||
| 742 | |||
| 743 | ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 744 | FLASH_ADDR_HIGH, 0x91); | ||
| 745 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 746 | FLASH_ADDR_LOW, 0xA0); | ||
| 747 | if (ret < 0) { | ||
| 748 | dev_err(dev, "IO error : set key flash address.\n"); | ||
| 749 | return ret; | ||
| 750 | } | ||
| 751 | |||
| 752 | ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 753 | FLASH_LEN_HIGH, (FLASH_BUF_LEN - 1) >> 8); | ||
| 754 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 755 | FLASH_LEN_LOW, (FLASH_BUF_LEN - 1) & 0xFF); | ||
| 756 | if (ret < 0) { | ||
| 757 | dev_err(dev, "IO error : set key flash len.\n"); | ||
| 758 | return ret; | ||
| 759 | } | ||
| 760 | |||
| 761 | ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 762 | R_FLASH_RW_CTRL, FLASH_READ); | ||
| 763 | ret |= readx_poll_timeout(anx7625_read_flash_status, | ||
| 764 | ctx, val, | ||
| 765 | ((val & FLASH_DONE) || (val < 0)), | ||
| 766 | 2000, | ||
| 767 | 2000 * 150); | ||
| 768 | if (ret) { | ||
| 769 | dev_err(dev, "flash read access fail!\n"); | ||
| 770 | return -EIO; | ||
| 771 | } | ||
| 772 | |||
| 773 | ret = anx7625_reg_block_read(ctx, ctx->i2c.rx_p0_client, | ||
| 774 | FLASH_BUF_BASE_ADDR, | ||
| 775 | FLASH_BUF_LEN, ident); | ||
| 776 | if (ret < 0) { | ||
| 777 | dev_err(dev, "read flash data fail!\n"); | ||
| 778 | return -EIO; | ||
| 779 | } | ||
| 780 | |||
| 781 | if (ident[29] == 0xFF && ident[30] == 0xFF && ident[31] == 0xFF) | ||
| 782 | return -EINVAL; | ||
| 783 | |||
| 784 | return 0; | ||
| 785 | } | ||
| 786 | |||
| 787 | static int anx7625_hdcp_key_load(struct anx7625_data *ctx) | ||
| 788 | { | ||
| 789 | int ret; | ||
| 790 | struct device *dev = &ctx->client->dev; | ||
| 791 | |||
| 792 | /* Select HDCP 1.4 KEY */ | ||
| 793 | ret = anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 794 | R_BOOT_RETRY, 0x12); | ||
| 795 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 796 | FLASH_ADDR_HIGH, HDCP14KEY_START_ADDR >> 8); | ||
| 797 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 798 | FLASH_ADDR_LOW, HDCP14KEY_START_ADDR & 0xFF); | ||
| 799 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 800 | R_RAM_LEN_H, HDCP14KEY_SIZE >> 12); | ||
| 801 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 802 | R_RAM_LEN_L, HDCP14KEY_SIZE >> 4); | ||
| 803 | |||
| 804 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 805 | R_RAM_ADDR_H, 0); | ||
| 806 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 807 | R_RAM_ADDR_L, 0); | ||
| 808 | /* Enable HDCP 1.4 KEY load */ | ||
| 809 | ret |= anx7625_reg_write(ctx, ctx->i2c.rx_p0_client, | ||
| 810 | R_RAM_CTRL, DECRYPT_EN | LOAD_START); | ||
| 811 | dev_dbg(dev, "load HDCP 1.4 key done\n"); | ||
| 812 | return ret; | ||
| 813 | } | ||
| 814 | |||
| 815 | static int anx7625_hdcp_disable(struct anx7625_data *ctx) | ||
| 816 | { | ||
| 817 | int ret; | ||
| 818 | struct device *dev = &ctx->client->dev; | ||
| 819 | |||
| 820 | dev_dbg(dev, "disable HDCP 1.4\n"); | ||
| 821 | |||
| 822 | /* Disable HDCP */ | ||
| 823 | ret = anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f); | ||
| 824 | /* Try auth flag */ | ||
| 825 | ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10); | ||
| 826 | /* Interrupt for DRM */ | ||
| 827 | ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01); | ||
| 828 | if (ret < 0) | ||
| 829 | dev_err(dev, "fail to disable HDCP\n"); | ||
| 830 | |||
| 831 | return anx7625_write_and(ctx, ctx->i2c.tx_p0_client, | ||
| 832 | TX_HDCP_CTRL0, ~HARD_AUTH_EN & 0xFF); | ||
| 833 | } | ||
| 834 | |||
| 835 | static int anx7625_hdcp_enable(struct anx7625_data *ctx) | ||
| 836 | { | ||
| 837 | u8 bcap; | ||
| 838 | int ret; | ||
| 839 | struct device *dev = &ctx->client->dev; | ||
| 840 | |||
| 841 | ret = anx7625_hdcp_key_probe(ctx); | ||
| 842 | if (ret) { | ||
| 843 | dev_dbg(dev, "no key found, not to do hdcp\n"); | ||
| 844 | return ret; | ||
| 845 | } | ||
| 846 | |||
| 847 | /* Read downstream capability */ | ||
| 848 | anx7625_aux_dpcd_read(ctx, 0x68028, 1, &bcap); | ||
| 849 | if (!(bcap & 0x01)) { | ||
| 850 | pr_warn("downstream not support HDCP 1.4, cap(%x).\n", bcap); | ||
| 851 | return 0; | ||
| 852 | } | ||
| 853 | |||
| 854 | dev_dbg(dev, "enable HDCP 1.4\n"); | ||
| 855 | |||
| 856 | /* First clear HDCP state */ | ||
| 857 | ret = anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||
| 858 | TX_HDCP_CTRL0, | ||
| 859 | KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN); | ||
| 860 | usleep_range(1000, 1100); | ||
| 861 | /* Second clear HDCP state */ | ||
| 862 | ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||
| 863 | TX_HDCP_CTRL0, | ||
| 864 | KSVLIST_VLD | BKSV_SRM_PASS | RE_AUTHEN); | ||
| 865 | |||
| 866 | /* Set time for waiting KSVR */ | ||
| 867 | ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||
| 868 | SP_TX_WAIT_KSVR_TIME, 0xc8); | ||
| 869 | /* Set time for waiting R0 */ | ||
| 870 | ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p0_client, | ||
| 871 | SP_TX_WAIT_R0_TIME, 0xb0); | ||
| 872 | ret |= anx7625_hdcp_key_load(ctx); | ||
| 873 | if (ret) { | ||
| 874 | pr_warn("prepare HDCP key failed.\n"); | ||
| 875 | return ret; | ||
| 876 | } | ||
| 877 | |||
| 878 | ret = anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xee, 0x20); | ||
| 879 | |||
| 880 | /* Try auth flag */ | ||
| 881 | ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xec, 0x10); | ||
| 882 | /* Interrupt for DRM */ | ||
| 883 | ret |= anx7625_write_or(ctx, ctx->i2c.rx_p1_client, 0xff, 0x01); | ||
| 884 | if (ret < 0) | ||
| 885 | dev_err(dev, "fail to enable HDCP\n"); | ||
| 886 | |||
| 887 | return anx7625_write_or(ctx, ctx->i2c.tx_p0_client, | ||
| 888 | TX_HDCP_CTRL0, HARD_AUTH_EN); | ||
| 889 | } | ||
| 890 | |||
| 672 | static void anx7625_dp_start(struct anx7625_data *ctx) | 891 | static void anx7625_dp_start(struct anx7625_data *ctx) |
| 673 | { | 892 | { |
| 674 | int ret; | 893 | int ret; |
| @@ -679,6 +898,9 @@ static void anx7625_dp_start(struct anx7625_data *ctx) · 4 unmodified lines | |||
| 679 | return; | 898 | return; |
| 680 | } | 899 | } |
| 681 | 900 | ||
| 901 | /* Disable HDCP */ | ||
| 902 | anx7625_write_and(ctx, ctx->i2c.rx_p1_client, 0xee, 0x9f); | ||
| 903 | |||
| 682 | if (ctx->pdata.is_dpi) | 904 | if (ctx->pdata.is_dpi) |
| 683 | ret = anx7625_dpi_config(ctx); | 905 | ret = anx7625_dpi_config(ctx); |
| 684 | else | 906 | else |
| @@ -686,6 +908,10 @@ static void anx7625_dp_start(struct anx7625_data *ctx) · 1 unmodified line | |||
| 686 | 908 | ||
| 687 | if (ret < 0) | 909 | if (ret < 0) |
| 688 | DRM_DEV_ERROR(dev, "MIPI phy setup error.\n"); | 910 | DRM_DEV_ERROR(dev, "MIPI phy setup error.\n"); |
| 911 | |||
| 912 | ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | ||
| 913 | |||
| 914 | ctx->dp_en = 1; | ||
| 689 | } | 915 | } |
| 690 | 916 | ||
| 691 | static void anx7625_dp_stop(struct anx7625_data *ctx) | 917 | static void anx7625_dp_stop(struct anx7625_data *ctx) |
| @@ -705,6 +931,10 @@ static void anx7625_dp_stop(struct anx7625_data *ctx) · 13 unmodified lines | |||
| 705 | ret |= anx7625_video_mute_control(ctx, 1); | 931 | ret |= anx7625_video_mute_control(ctx, 1); |
| 706 | if (ret < 0) | 932 | if (ret < 0) |
| 707 | DRM_DEV_ERROR(dev, "IO error : mute video fail\n"); | 933 | DRM_DEV_ERROR(dev, "IO error : mute video fail\n"); |
| 934 | |||
| 935 | ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | ||
| 936 | |||
| 937 | ctx->dp_en = 0; | ||
| 708 | } | 938 | } |
| 709 | 939 | ||
| 710 | static int sp_tx_rst_aux(struct anx7625_data *ctx) | 940 | static int sp_tx_rst_aux(struct anx7625_data *ctx) |
| @@ -1098,9 +1328,18 @@ static void anx7625_init_gpio(struct anx7625_data *platform) · 387 unmodified lines | |||
| 1098 | /* Gpio for chip power enable */ | 1328 | /* Gpio for chip power enable */ |
| 1099 | platform->pdata.gpio_p_on = | 1329 | platform->pdata.gpio_p_on = |
| 1100 | devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); | 1330 | devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_LOW); |
| 1331 | if (IS_ERR_OR_NULL(platform->pdata.gpio_p_on)) { | ||
| 1332 | DRM_DEV_DEBUG_DRIVER(dev, "no enable gpio found\n"); | ||
| 1333 | platform->pdata.gpio_p_on = NULL; | ||
| 1334 | } | ||
| 1335 | |||
| 1101 | /* Gpio for chip reset */ | 1336 | /* Gpio for chip reset */ |
| 1102 | platform->pdata.gpio_reset = | 1337 | platform->pdata.gpio_reset = |
| 1103 | devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); | 1338 | devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); |
| 1339 | if (IS_ERR_OR_NULL(platform->pdata.gpio_reset)) { | ||
| 1340 | DRM_DEV_DEBUG_DRIVER(dev, "no reset gpio found\n"); | ||
| 1341 | platform->pdata.gpio_reset = NULL; | ||
| 1342 | } | ||
| 1104 | 1343 | ||
| 1105 | if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) { | 1344 | if (platform->pdata.gpio_p_on && platform->pdata.gpio_reset) { |
| 1106 | platform->pdata.low_power_mode = 1; | 1345 | platform->pdata.low_power_mode = 1; |
| @@ -1601,9 +1840,27 @@ static int anx7625_audio_hook_plugged_cb(struct device *dev, void *data, · 494 unmodified lines | |||
| 1601 | return 0; | 1840 | return 0; |
| 1602 | } | 1841 | } |
| 1603 | 1842 | ||
| 1843 | static int anx7625_audio_get_eld(struct device *dev, void *data, | ||
| 1844 | u8 *buf, size_t len) | ||
| 1845 | { | ||
| 1846 | struct anx7625_data *ctx = dev_get_drvdata(dev); | ||
| 1847 | |||
| 1848 | if (!ctx->connector) { | ||
| 1849 | dev_err(dev, "connector not initial\n"); | ||
| 1850 | return -EINVAL; | ||
| 1851 | } | ||
| 1852 | |||
| 1853 | dev_dbg(dev, "audio copy eld\n"); | ||
| 1854 | memcpy(buf, ctx->connector->eld, | ||
| 1855 | min(sizeof(ctx->connector->eld), len)); | ||
| 1856 | |||
| 1857 | return 0; | ||
| 1858 | } | ||
| 1859 | |||
| 1604 | static const struct hdmi_codec_ops anx7625_codec_ops = { | 1860 | static const struct hdmi_codec_ops anx7625_codec_ops = { |
| 1605 | .hw_params = anx7625_audio_hw_params, | 1861 | .hw_params = anx7625_audio_hw_params, |
| 1606 | .audio_shutdown = anx7625_audio_shutdown, | 1862 | .audio_shutdown = anx7625_audio_shutdown, |
| 1863 | .get_eld = anx7625_audio_get_eld, | ||
| 1607 | .get_dai_id = anx7625_hdmi_i2s_get_dai_id, | 1864 | .get_dai_id = anx7625_hdmi_i2s_get_dai_id, |
| 1608 | .hook_plugged_cb = anx7625_audio_hook_plugged_cb, | 1865 | .hook_plugged_cb = anx7625_audio_hook_plugged_cb, |
| 1609 | }; | 1866 | }; |
| @@ -1660,7 +1917,7 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) · 50 unmodified lines | |||
| 1660 | host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); | 1917 | host = of_find_mipi_dsi_host_by_node(ctx->pdata.mipi_host_node); |
| 1661 | if (!host) { | 1918 | if (!host) { |
| 1662 | DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); | 1919 | DRM_DEV_ERROR(dev, "fail to find dsi host.\n"); |
| 1663 | return -EINVAL; | 1920 | return -EPROBE_DEFER; |
| 1664 | } | 1921 | } |
| 1665 | 1922 | ||
| 1666 | dsi = devm_mipi_dsi_device_register_full(dev, host, &info); | 1923 | dsi = devm_mipi_dsi_device_register_full(dev, host, &info); |
| @@ -1688,6 +1945,83 @@ static int anx7625_attach_dsi(struct anx7625_data *ctx) · 21 unmodified lines | |||
| 1688 | return 0; | 1945 | return 0; |
| 1689 | } | 1946 | } |
| 1690 | 1947 | ||
| 1948 | static void hdcp_check_work_func(struct work_struct *work) | ||
| 1949 | { | ||
| 1950 | u8 status; | ||
| 1951 | struct delayed_work *dwork; | ||
| 1952 | struct anx7625_data *ctx; | ||
| 1953 | struct device *dev; | ||
| 1954 | struct drm_device *drm_dev; | ||
| 1955 | |||
| 1956 | dwork = to_delayed_work(work); | ||
| 1957 | ctx = container_of(dwork, struct anx7625_data, hdcp_work); | ||
| 1958 | dev = &ctx->client->dev; | ||
| 1959 | |||
| 1960 | if (!ctx->connector) { | ||
| 1961 | dev_err(dev, "HDCP connector is null!"); | ||
| 1962 | return; | ||
| 1963 | } | ||
| 1964 | |||
| 1965 | drm_dev = ctx->connector->dev; | ||
| 1966 | drm_modeset_lock(&drm_dev->mode_config.connection_mutex, NULL); | ||
| 1967 | mutex_lock(&ctx->hdcp_wq_lock); | ||
| 1968 | |||
| 1969 | status = anx7625_reg_read(ctx, ctx->i2c.tx_p0_client, 0); | ||
| 1970 | dev_dbg(dev, "sink HDCP status check: %.02x\n", status); | ||
| 1971 | if (status & BIT(1)) { | ||
| 1972 | ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_ENABLED; | ||
| 1973 | drm_hdcp_update_content_protection(ctx->connector, | ||
| 1974 | ctx->hdcp_cp); | ||
| 1975 | dev_dbg(dev, "update CP to ENABLE\n"); | ||
| 1976 | } | ||
| 1977 | |||
| 1978 | mutex_unlock(&ctx->hdcp_wq_lock); | ||
| 1979 | drm_modeset_unlock(&drm_dev->mode_config.connection_mutex); | ||
| 1980 | } | ||
| 1981 | |||
| 1982 | static int anx7625_connector_atomic_check(struct anx7625_data *ctx, | ||
| 1983 | struct drm_connector_state *state) | ||
| 1984 | { | ||
| 1985 | struct device *dev = &ctx->client->dev; | ||
| 1986 | int cp; | ||
| 1987 | |||
| 1988 | dev_dbg(dev, "hdcp state check\n"); | ||
| 1989 | cp = state->content_protection; | ||
| 1990 | |||
| 1991 | if (cp == ctx->hdcp_cp) | ||
| 1992 | return 0; | ||
| 1993 | |||
| 1994 | if (cp == DRM_MODE_CONTENT_PROTECTION_DESIRED) { | ||
| 1995 | if (ctx->dp_en) { | ||
| 1996 | dev_dbg(dev, "enable HDCP\n"); | ||
| 1997 | anx7625_hdcp_enable(ctx); | ||
| 1998 | |||
| 1999 | queue_delayed_work(ctx->hdcp_workqueue, | ||
| 2000 | &ctx->hdcp_work, | ||
| 2001 | msecs_to_jiffies(2000)); | ||
| 2002 | } | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | if (cp == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { | ||
| 2006 | if (ctx->hdcp_cp != DRM_MODE_CONTENT_PROTECTION_ENABLED) { | ||
| 2007 | dev_err(dev, "current CP is not ENABLED\n"); | ||
| 2008 | return -EINVAL; | ||
| 2009 | } | ||
| 2010 | anx7625_hdcp_disable(ctx); | ||
| 2011 | ctx->hdcp_cp = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; | ||
| 2012 | drm_hdcp_update_content_protection(ctx->connector, | ||
| 2013 | ctx->hdcp_cp); | ||
| 2014 | dev_dbg(dev, "update CP to UNDESIRE\n"); | ||
| 2015 | } | ||
| 2016 | |||
| 2017 | if (cp == DRM_MODE_CONTENT_PROTECTION_ENABLED) { | ||
| 2018 | dev_err(dev, "Userspace illegal set to PROTECTION ENABLE\n"); | ||
| 2019 | return -EINVAL; | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | return 0; | ||
| 2023 | } | ||
| 2024 | |||
| 1691 | static int anx7625_bridge_attach(struct drm_bridge *bridge, | 2025 | static int anx7625_bridge_attach(struct drm_bridge *bridge, |
| 1692 | enum drm_bridge_attach_flags flags) | 2026 | enum drm_bridge_attach_flags flags) |
| 1693 | { | 2027 | { |
| @@ -1902,25 +2236,57 @@ static bool anx7625_bridge_mode_fixup(struct drm_bridge *bridge, · 208 unmodified lines | |||
| 1902 | return true; | 2236 | return true; |
| 1903 | } | 2237 | } |
| 1904 | 2238 | ||
| 1905 | static void anx7625_bridge_enable(struct drm_bridge *bridge) | 2239 | static int anx7625_bridge_atomic_check(struct drm_bridge *bridge, |
| 2240 | struct drm_bridge_state *bridge_state, | ||
| 2241 | struct drm_crtc_state *crtc_state, | ||
| 2242 | struct drm_connector_state *conn_state) | ||
| 2243 | { | ||
| 2244 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); | ||
| 2245 | struct device *dev = &ctx->client->dev; | ||
| 2246 | |||
| 2247 | dev_dbg(dev, "drm bridge atomic check\n"); | ||
| 2248 | |||
| 2249 | anx7625_bridge_mode_fixup(bridge, &crtc_state->mode, | ||
| 2250 | &crtc_state->adjusted_mode); | ||
| 2251 | |||
| 2252 | return anx7625_connector_atomic_check(ctx, conn_state); | ||
| 2253 | } | ||
| 2254 | |||
| 2255 | static void anx7625_bridge_atomic_enable(struct drm_bridge *bridge, | ||
| 2256 | struct drm_bridge_state *state) | ||
| 1906 | { | 2257 | { |
| 1907 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); | 2258 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); |
| 1908 | struct device *dev = &ctx->client->dev; | 2259 | struct device *dev = &ctx->client->dev; |
| 2260 | struct drm_connector *connector; | ||
| 1909 | 2261 | ||
| 1910 | DRM_DEV_DEBUG_DRIVER(dev, "drm enable\n"); | 2262 | dev_dbg(dev, "drm atomic enable\n"); |
| 2263 | |||
| 2264 | if (!bridge->encoder) { | ||
| 2265 | dev_err(dev, "Parent encoder object not found"); | ||
| 2266 | return; | ||
| 2267 | } | ||
| 2268 | |||
| 2269 | connector = drm_atomic_get_new_connector_for_encoder(state->base.state, | ||
| 2270 | bridge->encoder); | ||
| 2271 | if (!connector) | ||
| 2272 | return; | ||
| 2273 | |||
| 2274 | ctx->connector = connector; | ||
| 1911 | 2275 | ||
| 1912 | pm_runtime_get_sync(dev); | 2276 | pm_runtime_get_sync(dev); |
| 1913 | 2277 | ||
| 1914 | anx7625_dp_start(ctx); | 2278 | anx7625_dp_start(ctx); |
| 1915 | } | 2279 | } |
| 1916 | 2280 | ||
| 1917 | static void anx7625_bridge_disable(struct drm_bridge *bridge) | 2281 | static void anx7625_bridge_atomic_disable(struct drm_bridge *bridge, |
| 2282 | struct drm_bridge_state *old) | ||
| 1918 | { | 2283 | { |
| 1919 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); | 2284 | struct anx7625_data *ctx = bridge_to_anx7625(bridge); |
| 1920 | struct device *dev = &ctx->client->dev; | 2285 | struct device *dev = &ctx->client->dev; |
| 1921 | 2286 | ||
| 1922 | DRM_DEV_DEBUG_DRIVER(dev, "drm disable\n"); | 2287 | dev_dbg(dev, "drm atomic disable\n"); |
| 1923 | 2288 | ||
| 2289 | ctx->connector = NULL; | ||
| 1924 | anx7625_dp_stop(ctx); | 2290 | anx7625_dp_stop(ctx); |
| 1925 | 2291 | ||
| 1926 | pm_runtime_put_sync(dev); | 2292 | pm_runtime_put_sync(dev); |
| @@ -1950,11 +2316,14 @@ static struct edid *anx7625_bridge_get_edid(struct drm_bridge *bridge, · 23 unmodified lines | |||
| 1950 | 2316 | ||
| 1951 | static const struct drm_bridge_funcs anx7625_bridge_funcs = { | 2317 | static const struct drm_bridge_funcs anx7625_bridge_funcs = { |
| 1952 | .attach = anx7625_bridge_attach, | 2318 | .attach = anx7625_bridge_attach, |
| 1953 | .disable = anx7625_bridge_disable, | ||
| 1954 | .mode_valid = anx7625_bridge_mode_valid, | 2319 | .mode_valid = anx7625_bridge_mode_valid, |
| 1955 | .mode_set = anx7625_bridge_mode_set, | 2320 | .mode_set = anx7625_bridge_mode_set, |
| 1956 | .mode_fixup = anx7625_bridge_mode_fixup, | 2321 | .atomic_check = anx7625_bridge_atomic_check, |
| 1957 | .enable = anx7625_bridge_enable, | 2322 | .atomic_enable = anx7625_bridge_atomic_enable, |
| 2323 | .atomic_disable = anx7625_bridge_atomic_disable, | ||
| 2324 | .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, | ||
| 2325 | .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, | ||
| 2326 | .atomic_reset = drm_atomic_helper_bridge_reset, | ||
| 1958 | .detect = anx7625_bridge_detect, | 2327 | .detect = anx7625_bridge_detect, |
| 1959 | .get_edid = anx7625_bridge_get_edid, | 2328 | .get_edid = anx7625_bridge_get_edid, |
| 1960 | }; | 2329 | }; |
| @@ -1962,40 +2331,54 @@ static const struct drm_bridge_funcs anx7625_bridge_funcs = { · 1 unmodified line | |||
| 1962 | static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, | 2331 | static int anx7625_register_i2c_dummy_clients(struct anx7625_data *ctx, |
| 1963 | struct i2c_client *client) | 2332 | struct i2c_client *client) |
| 1964 | { | 2333 | { |
| 2334 | int err = 0; | ||
| 2335 | |||
| 1965 | ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter, | 2336 | ctx->i2c.tx_p0_client = i2c_new_dummy_device(client->adapter, |
| 1966 | TX_P0_ADDR >> 1); | 2337 | TX_P0_ADDR >> 1); |
| 1967 | if (!ctx->i2c.tx_p0_client) | 2338 | if (IS_ERR(ctx->i2c.tx_p0_client)) |
| 1968 | return -ENOMEM; | 2339 | return PTR_ERR(ctx->i2c.tx_p0_client); |
| 1969 | 2340 | ||
| 1970 | ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter, | 2341 | ctx->i2c.tx_p1_client = i2c_new_dummy_device(client->adapter, |
| 1971 | TX_P1_ADDR >> 1); | 2342 | TX_P1_ADDR >> 1); |
| 1972 | if (!ctx->i2c.tx_p1_client) | 2343 | if (IS_ERR(ctx->i2c.tx_p1_client)) { |
| 2344 | err = PTR_ERR(ctx->i2c.tx_p1_client); | ||
| 1973 | goto free_tx_p0; | 2345 | goto free_tx_p0; |
| 2346 | } | ||
| 1974 | 2347 | ||
| 1975 | ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter, | 2348 | ctx->i2c.tx_p2_client = i2c_new_dummy_device(client->adapter, |
| 1976 | TX_P2_ADDR >> 1); | 2349 | TX_P2_ADDR >> 1); |
| 1977 | if (!ctx->i2c.tx_p2_client) | 2350 | if (IS_ERR(ctx->i2c.tx_p2_client)) { |
| 2351 | err = PTR_ERR(ctx->i2c.tx_p2_client); | ||
| 1978 | goto free_tx_p1; | 2352 | goto free_tx_p1; |
| 2353 | } | ||
| 1979 | 2354 | ||
| 1980 | ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter, | 2355 | ctx->i2c.rx_p0_client = i2c_new_dummy_device(client->adapter, |
| 1981 | RX_P0_ADDR >> 1); | 2356 | RX_P0_ADDR >> 1); |
| 1982 | if (!ctx->i2c.rx_p0_client) | 2357 | if (IS_ERR(ctx->i2c.rx_p0_client)) { |
| 2358 | err = PTR_ERR(ctx->i2c.rx_p0_client); | ||
| 1983 | goto free_tx_p2; | 2359 | goto free_tx_p2; |
| 2360 | } | ||
| 1984 | 2361 | ||
| 1985 | ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter, | 2362 | ctx->i2c.rx_p1_client = i2c_new_dummy_device(client->adapter, |
| 1986 | RX_P1_ADDR >> 1); | 2363 | RX_P1_ADDR >> 1); |
| 1987 | if (!ctx->i2c.rx_p1_client) | 2364 | if (IS_ERR(ctx->i2c.rx_p1_client)) { |
| 2365 | err = PTR_ERR(ctx->i2c.rx_p1_client); | ||
| 1988 | goto free_rx_p0; | 2366 | goto free_rx_p0; |
| 2367 | } | ||
| 1989 | 2368 | ||
| 1990 | ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter, | 2369 | ctx->i2c.rx_p2_client = i2c_new_dummy_device(client->adapter, |
| 1991 | RX_P2_ADDR >> 1); | 2370 | RX_P2_ADDR >> 1); |
| 1992 | if (!ctx->i2c.rx_p2_client) | 2371 | if (IS_ERR(ctx->i2c.rx_p2_client)) { |
| 2372 | err = PTR_ERR(ctx->i2c.rx_p2_client); | ||
| 1993 | goto free_rx_p1; | 2373 | goto free_rx_p1; |
| 2374 | } | ||
| 1994 | 2375 | ||
| 1995 | ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter, | 2376 | ctx->i2c.tcpc_client = i2c_new_dummy_device(client->adapter, |
| 1996 | TCPC_INTERFACE_ADDR >> 1); | 2377 | TCPC_INTERFACE_ADDR >> 1); |
| 1997 | if (!ctx->i2c.tcpc_client) | 2378 | if (IS_ERR(ctx->i2c.tcpc_client)) { |
| 2379 | err = PTR_ERR(ctx->i2c.tcpc_client); | ||
| 1998 | goto free_rx_p2; | 2380 | goto free_rx_p2; |
| 2381 | } | ||
| 1999 | 2382 | ||
| 2000 | return 0; | 2383 | return 0; |
| 2001 | 2384 | ||
| @@ -2012,7 +2395,7 @@ free_tx_p1: · 10 unmodified lines | |||
| 2012 | free_tx_p0: | 2395 | free_tx_p0: |
| 2013 | i2c_unregister_device(ctx->i2c.tx_p0_client); | 2396 | i2c_unregister_device(ctx->i2c.tx_p0_client); |
| 2014 | 2397 | ||
| 2015 | return -ENOMEM; | 2398 | return err; |
| 2016 | } | 2399 | } |
| 2017 | 2400 | ||
| 2018 | static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) | 2401 | static void anx7625_unregister_i2c_dummy_clients(struct anx7625_data *ctx) |
| @@ -2134,6 +2517,15 @@ static int anx7625_i2c_probe(struct i2c_client *client, · 115 unmodified lines | |||
| 2134 | anx7625_init_gpio(platform); | 2517 | anx7625_init_gpio(platform); |
| 2135 | 2518 | ||
| 2136 | mutex_init(&platform->lock); | 2519 | mutex_init(&platform->lock); |
| 2520 | mutex_init(&platform->hdcp_wq_lock); | ||
| 2521 | |||
| 2522 | INIT_DELAYED_WORK(&platform->hdcp_work, hdcp_check_work_func); | ||
| 2523 | platform->hdcp_workqueue = create_workqueue("hdcp workqueue"); | ||
| 2524 | if (!platform->hdcp_workqueue) { | ||
| 2525 | dev_err(dev, "fail to create work queue\n"); | ||
| 2526 | ret = -ENOMEM; | ||
| 2527 | goto free_platform; | ||
| 2528 | } | ||
| 2137 | 2529 | ||
| 2138 | platform->pdata.intp_irq = client->irq; | 2530 | platform->pdata.intp_irq = client->irq; |
| 2139 | if (platform->pdata.intp_irq) { | 2531 | if (platform->pdata.intp_irq) { |
| @@ -2143,7 +2535,7 @@ static int anx7625_i2c_probe(struct i2c_client *client, · 3 unmodified lines | |||
| 2143 | if (!platform->workqueue) { | 2535 | if (!platform->workqueue) { |
| 2144 | DRM_DEV_ERROR(dev, "fail to create work queue\n"); | 2536 | DRM_DEV_ERROR(dev, "fail to create work queue\n"); |
| 2145 | ret = -ENOMEM; | 2537 | ret = -ENOMEM; |
| 2146 | goto free_platform; | 2538 | goto free_hdcp_wq; |
| 2147 | } | 2539 | } |
| 2148 | 2540 | ||
| 2149 | ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq, | 2541 | ret = devm_request_threaded_irq(dev, platform->pdata.intp_irq, |
| @@ -2213,6 +2605,10 @@ free_wq: · 63 unmodified lines | |||
| 2213 | if (platform->workqueue) | 2605 | if (platform->workqueue) |
| 2214 | destroy_workqueue(platform->workqueue); | 2606 | destroy_workqueue(platform->workqueue); |
| 2215 | 2607 | ||
| 2608 | free_hdcp_wq: | ||
| 2609 | if (platform->hdcp_workqueue) | ||
| 2610 | destroy_workqueue(platform->hdcp_workqueue); | ||
| 2611 | |||
| 2216 | free_platform: | 2612 | free_platform: |
| 2217 | kfree(platform); | 2613 | kfree(platform); |
| 2218 | 2614 | ||
| @@ -2228,6 +2624,12 @@ static int anx7625_i2c_remove(struct i2c_client *client) · 9 unmodified lines | |||
| 2228 | if (platform->pdata.intp_irq) | 2624 | if (platform->pdata.intp_irq) |
| 2229 | destroy_workqueue(platform->workqueue); | 2625 | destroy_workqueue(platform->workqueue); |
| 2230 | 2626 | ||
| 2627 | if (platform->hdcp_workqueue) { | ||
| 2628 | cancel_delayed_work(&platform->hdcp_work); | ||
| 2629 | flush_workqueue(platform->workqueue); | ||
| 2630 | destroy_workqueue(platform->workqueue); | ||
| 2631 | } | ||
| 2632 | |||
| 2231 | if (!platform->pdata.low_power_mode) | 2633 | if (!platform->pdata.low_power_mode) |
| 2232 | pm_runtime_put_sync_suspend(&client->dev); | 2634 | pm_runtime_put_sync_suspend(&client->dev); |
| 2233 | 2635 | ||
| @@ -59,10 +59,23 @@ · 58 unmodified lines | |||
| 59 | 59 | ||
| 60 | /***************************************************************/ | 60 | /***************************************************************/ |
| 61 | /* Register definition of device address 0x70 */ | 61 | /* Register definition of device address 0x70 */ |
| 62 | #define I2C_ADDR_70_DPTX 0x70 | 62 | #define TX_HDCP_CTRL0 0x01 |
| 63 | 63 | #define STORE_AN BIT(7) | |
| 64 | #define SP_TX_LINK_BW_SET_REG 0xA0 | 64 | #define RX_REPEATER BIT(6) |
| 65 | #define SP_TX_LANE_COUNT_SET_REG 0xA1 | 65 | #define RE_AUTHEN BIT(5) |
| 66 | #define SW_AUTH_OK BIT(4) | ||
| 67 | #define HARD_AUTH_EN BIT(3) | ||
| 68 | #define ENC_EN BIT(2) | ||
| 69 | #define BKSV_SRM_PASS BIT(1) | ||
| 70 | #define KSVLIST_VLD BIT(0) | ||
| 71 | |||
| 72 | #define SP_TX_WAIT_R0_TIME 0x40 | ||
| 73 | #define SP_TX_WAIT_KSVR_TIME 0x42 | ||
| 74 | #define SP_TX_SYS_CTRL1_REG 0x80 | ||
| 75 | #define HDCP2TX_FW_EN BIT(4) | ||
| 76 | |||
| 77 | #define SP_TX_LINK_BW_SET_REG 0xA0 | ||
| 78 | #define SP_TX_LANE_COUNT_SET_REG 0xA1 | ||
| 66 | 79 | ||
| 67 | #define M_VID_0 0xC0 | 80 | #define M_VID_0 0xC0 |
| 68 | #define M_VID_1 0xC1 | 81 | #define M_VID_1 0xC1 |
| @@ -71,6 +84,12 @@ · 2 unmodified lines | |||
| 71 | #define N_VID_1 0xC4 | 84 | #define N_VID_1 0xC4 |
| 72 | #define N_VID_2 0xC5 | 85 | #define N_VID_2 0xC5 |
| 73 | 86 | ||
| 87 | #define KEY_START_ADDR 0x9000 | ||
| 88 | #define KEY_RESERVED 416 | ||
| 89 | |||
| 90 | #define HDCP14KEY_START_ADDR (KEY_START_ADDR + KEY_RESERVED) | ||
| 91 | #define HDCP14KEY_SIZE 624 | ||
| 92 | |||
| 74 | /***************************************************************/ | 93 | /***************************************************************/ |
| 75 | /* Register definition of device address 0x72 */ | 94 | /* Register definition of device address 0x72 */ |
| 76 | #define AUX_RST 0x04 | 95 | #define AUX_RST 0x04 |
| @@ -155,9 +174,43 @@ · 78 unmodified lines | |||
| 155 | 174 | ||
| 156 | #define I2C_ADDR_7E_FLASH_CONTROLLER 0x7E | 175 | #define I2C_ADDR_7E_FLASH_CONTROLLER 0x7E |
| 157 | 176 | ||
| 177 | #define R_BOOT_RETRY 0x00 | ||
| 178 | #define R_RAM_ADDR_H 0x01 | ||
| 179 | #define R_RAM_ADDR_L 0x02 | ||
| 180 | #define R_RAM_LEN_H 0x03 | ||
| 181 | #define R_RAM_LEN_L 0x04 | ||
| 158 | #define FLASH_LOAD_STA 0x05 | 182 | #define FLASH_LOAD_STA 0x05 |
| 159 | #define FLASH_LOAD_STA_CHK BIT(7) | 183 | #define FLASH_LOAD_STA_CHK BIT(7) |
| 160 | 184 | ||
| 185 | #define R_RAM_CTRL 0x05 | ||
| 186 | /* bit positions */ | ||
| 187 | #define FLASH_DONE BIT(7) | ||
| 188 | #define BOOT_LOAD_DONE BIT(6) | ||
| 189 | #define CRC_OK BIT(5) | ||
| 190 | #define LOAD_DONE BIT(4) | ||
| 191 | #define O_RW_DONE BIT(3) | ||
| 192 | #define FUSE_BUSY BIT(2) | ||
| 193 | #define DECRYPT_EN BIT(1) | ||
| 194 | #define LOAD_START BIT(0) | ||
| 195 | |||
| 196 | #define FLASH_ADDR_HIGH 0x0F | ||
| 197 | #define FLASH_ADDR_LOW 0x10 | ||
| 198 | #define FLASH_LEN_HIGH 0x31 | ||
| 199 | #define FLASH_LEN_LOW 0x32 | ||
| 200 | #define R_FLASH_RW_CTRL 0x33 | ||
| 201 | /* bit positions */ | ||
| 202 | #define READ_DELAY_SELECT BIT(7) | ||
| 203 | #define GENERAL_INSTRUCTION_EN BIT(6) | ||
| 204 | #define FLASH_ERASE_EN BIT(5) | ||
| 205 | #define RDID_READ_EN BIT(4) | ||
| 206 | #define REMS_READ_EN BIT(3) | ||
| 207 | #define WRITE_STATUS_EN BIT(2) | ||
| 208 | #define FLASH_READ BIT(1) | ||
| 209 | #define FLASH_WRITE BIT(0) | ||
| 210 | |||
| 211 | #define FLASH_BUF_BASE_ADDR 0x60 | ||
| 212 | #define FLASH_BUF_LEN 0x20 | ||
| 213 | |||
| 161 | #define XTAL_FRQ_SEL 0x3F | 214 | #define XTAL_FRQ_SEL 0x3F |
| 162 | /* bit field positions */ | 215 | /* bit field positions */ |
| 163 | #define XTAL_FRQ_SEL_POS 5 | 216 | #define XTAL_FRQ_SEL_POS 5 |
| @@ -184,10 +237,15 @@ · 20 unmodified lines | |||
| 184 | #define AP_AUX_CTRL_ADDRONLY 0x20 | 237 | #define AP_AUX_CTRL_ADDRONLY 0x20 |
| 185 | 238 | ||
| 186 | #define AP_AUX_BUFF_START 0x15 | 239 | #define AP_AUX_BUFF_START 0x15 |
| 187 | #define PIXEL_CLOCK_L 0x25 | 240 | #define PIXEL_CLOCK_L 0x25 |
| 188 | #define PIXEL_CLOCK_H 0x26 | 241 | #define PIXEL_CLOCK_H 0x26 |
| 242 | |||
| 243 | #define AP_AUX_COMMAND 0x27 /* com+len */ | ||
| 244 | #define LENGTH_SHIFT 4 | ||
| 245 | #define DPCD_READ 0x09 | ||
| 246 | #define DPCD_WRITE 0x08 | ||
| 247 | #define DPCD_CMD(len, cmd) ((((len) - 1) << LENGTH_SHIFT) | (cmd)) | ||
| 189 | 248 | ||
| 190 | #define AP_AUX_COMMAND 0x27 /* com+len */ | ||
| 191 | /* Bit 0&1: 3D video structure */ | 249 | /* Bit 0&1: 3D video structure */ |
| 192 | /* 0x01: frame packing, 0x02:Line alternative, 0x03:Side-by-side(full) */ | 250 | /* 0x01: frame packing, 0x02:Line alternative, 0x03:Side-by-side(full) */ |
| 193 | #define AP_AV_STATUS 0x28 | 251 | #define AP_AV_STATUS 0x28 |
| @@ -392,21 +450,29 @@ struct anx7625_data { · 198 unmodified lines | |||
| 392 | struct platform_device *audio_pdev; | 450 | struct platform_device *audio_pdev; |
| 393 | int hpd_status; | 451 | int hpd_status; |
| 394 | int hpd_high_cnt; | 452 | int hpd_high_cnt; |
| 453 | int dp_en; | ||
| 454 | int hdcp_cp; | ||
| 395 | /* Lock for work queue */ | 455 | /* Lock for work queue */ |
| 396 | struct mutex lock; | 456 | struct mutex lock; |
| 397 | struct i2c_client *client; | 457 | struct i2c_client *client; |
| 398 | struct anx7625_i2c_client i2c; | 458 | struct anx7625_i2c_client i2c; |
| 399 | struct i2c_client *last_client; | 459 | struct i2c_client *last_client; |
| 460 | struct timer_list hdcp_timer; | ||
| 400 | struct s_edid_data slimport_edid_p; | 461 | struct s_edid_data slimport_edid_p; |
| 401 | struct device *codec_dev; | 462 | struct device *codec_dev; |
| 402 | hdmi_codec_plugged_cb plugged_cb; | 463 | hdmi_codec_plugged_cb plugged_cb; |
| 403 | struct work_struct work; | 464 | struct work_struct work; |
| 404 | struct workqueue_struct *workqueue; | 465 | struct workqueue_struct *workqueue; |
| 466 | struct delayed_work hdcp_work; | ||
| 467 | struct workqueue_struct *hdcp_workqueue; | ||
| 468 | /* Lock for hdcp work queue */ | ||
| 469 | struct mutex hdcp_wq_lock; | ||
| 405 | char edid_block; | 470 | char edid_block; |
| 406 | struct display_timing dt; | 471 | struct display_timing dt; |
| 407 | u8 display_timing_valid; | 472 | u8 display_timing_valid; |
| 408 | struct drm_bridge bridge; | 473 | struct drm_bridge bridge; |
| 409 | u8 bridge_attached; | 474 | u8 bridge_attached; |
| 475 | struct drm_connector *connector; | ||
| 410 | struct mipi_dsi_device *dsi; | 476 | struct mipi_dsi_device *dsi; |
| 411 | }; | 477 | }; |
| 412 | 478 | ||
| @@ -1,6 +1,7 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-only | 1 | # SPDX-License-Identifier: GPL-2.0-only |
| 2 | config DRM_CDNS_MHDP8546 | 2 | config DRM_CDNS_MHDP8546 |
| 3 | tristate "Cadence DPI/DP bridge" | 3 | tristate "Cadence DPI/DP bridge" |
| 4 | select DRM_DP_HELPER | ||
| 4 | select DRM_KMS_HELPER | 5 | select DRM_KMS_HELPER |
| 5 | select DRM_PANEL_BRIDGE | 6 | select DRM_PANEL_BRIDGE |
| 6 | depends on OF | 7 | depends on OF |
| @@ -41,7 +41,7 @@ · 40 unmodified lines | |||
| 41 | #include <drm/drm_bridge.h> | 41 | #include <drm/drm_bridge.h> |
| 42 | #include <drm/drm_connector.h> | 42 | #include <drm/drm_connector.h> |
| 43 | #include <drm/drm_crtc_helper.h> | 43 | #include <drm/drm_crtc_helper.h> |
| 44 | #include <drm/drm_dp_helper.h> | 44 | #include <drm/dp/drm_dp_helper.h> |
| 45 | #include <drm/drm_hdcp.h> | 45 | #include <drm/drm_hdcp.h> |
| 46 | #include <drm/drm_modeset_helper_vtables.h> | 46 | #include <drm/drm_modeset_helper_vtables.h> |
| 47 | #include <drm/drm_print.h> | 47 | #include <drm/drm_print.h> |
| @@ -1553,13 +1553,13 @@ static u32 cdns_mhdp_get_bpp(struct cdns_mhdp_display_fmt *fmt) · 1505 unmodified lines | |||
| 1553 | 1553 | ||
| 1554 | switch (fmt->color_format) { | 1554 | switch (fmt->color_format) { |
| 1555 | case DRM_COLOR_FORMAT_RGB444: | 1555 | case DRM_COLOR_FORMAT_RGB444: |
| 1556 | case DRM_COLOR_FORMAT_YCRCB444: | 1556 | case DRM_COLOR_FORMAT_YCBCR444: |
| 1557 | bpp = fmt->bpc * 3; | 1557 | bpp = fmt->bpc * 3; |
| 1558 | break; | 1558 | break; |
| 1559 | case DRM_COLOR_FORMAT_YCRCB422: | 1559 | case DRM_COLOR_FORMAT_YCBCR422: |
| 1560 | bpp = fmt->bpc * 2; | 1560 | bpp = fmt->bpc * 2; |
| 1561 | break; | 1561 | break; |
| 1562 | case DRM_COLOR_FORMAT_YCRCB420: | 1562 | case DRM_COLOR_FORMAT_YCBCR420: |
| 1563 | bpp = fmt->bpc * 3 / 2; | 1563 | bpp = fmt->bpc * 3 / 2; |
| 1564 | break; | 1564 | break; |
| 1565 | default: | 1565 | default: |
| @@ -1767,8 +1767,8 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, · 201 unmodified lines | |||
| 1767 | * If YCBCR supported and stream not SD, use ITU709 | 1767 | * If YCBCR supported and stream not SD, use ITU709 |
| 1768 | * Need to handle ITU version with YCBCR420 when supported | 1768 | * Need to handle ITU version with YCBCR420 when supported |
| 1769 | */ | 1769 | */ |
| 1770 | if ((pxlfmt == DRM_COLOR_FORMAT_YCRCB444 || | 1770 | if ((pxlfmt == DRM_COLOR_FORMAT_YCBCR444 || |
| 1771 | pxlfmt == DRM_COLOR_FORMAT_YCRCB422) && mode->crtc_vdisplay >= 720) | 1771 | pxlfmt == DRM_COLOR_FORMAT_YCBCR422) && mode->crtc_vdisplay >= 720) |
| 1772 | misc0 = DP_YCBCR_COEFFICIENTS_ITU709; | 1772 | misc0 = DP_YCBCR_COEFFICIENTS_ITU709; |
| 1773 | 1773 | ||
| 1774 | bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt); | 1774 | bpp = cdns_mhdp_get_bpp(&mhdp->display_fmt); |
| @@ -1778,15 +1778,15 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, · 3 unmodified lines | |||
| 1778 | pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT; | 1778 | pxl_repr = CDNS_DP_FRAMER_RGB << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1779 | misc0 |= DP_COLOR_FORMAT_RGB; | 1779 | misc0 |= DP_COLOR_FORMAT_RGB; |
| 1780 | break; | 1780 | break; |
| 1781 | case DRM_COLOR_FORMAT_YCRCB444: | 1781 | case DRM_COLOR_FORMAT_YCBCR444: |
| 1782 | pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT; | 1782 | pxl_repr = CDNS_DP_FRAMER_YCBCR444 << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1783 | misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA; | 1783 | misc0 |= DP_COLOR_FORMAT_YCbCr444 | DP_TEST_DYNAMIC_RANGE_CEA; |
| 1784 | break; | 1784 | break; |
| 1785 | case DRM_COLOR_FORMAT_YCRCB422: | 1785 | case DRM_COLOR_FORMAT_YCBCR422: |
| 1786 | pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT; | 1786 | pxl_repr = CDNS_DP_FRAMER_YCBCR422 << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1787 | misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA; | 1787 | misc0 |= DP_COLOR_FORMAT_YCbCr422 | DP_TEST_DYNAMIC_RANGE_CEA; |
| 1788 | break; | 1788 | break; |
| 1789 | case DRM_COLOR_FORMAT_YCRCB420: | 1789 | case DRM_COLOR_FORMAT_YCBCR420: |
| 1790 | pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT; | 1790 | pxl_repr = CDNS_DP_FRAMER_YCBCR420 << CDNS_DP_FRAMER_PXL_FORMAT; |
| 1791 | break; | 1791 | break; |
| 1792 | default: | 1792 | default: |
| @@ -1882,7 +1882,7 @@ static void cdns_mhdp_configure_video(struct cdns_mhdp_device *mhdp, · 89 unmodified lines | |||
| 1882 | if (mhdp->display_fmt.y_only) | 1882 | if (mhdp->display_fmt.y_only) |
| 1883 | misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY; | 1883 | misc1 |= CDNS_DP_TEST_COLOR_FORMAT_RAW_Y_ONLY; |
| 1884 | /* Use VSC SDP for Y420 */ | 1884 | /* Use VSC SDP for Y420 */ |
| 1885 | if (pxlfmt == DRM_COLOR_FORMAT_YCRCB420) | 1885 | if (pxlfmt == DRM_COLOR_FORMAT_YCBCR420) |
| 1886 | misc1 = CDNS_DP_TEST_VSC_SDP; | 1886 | misc1 = CDNS_DP_TEST_VSC_SDP; |
| 1887 | 1887 | ||
| 1888 | cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id), | 1888 | cdns_mhdp_reg_write(mhdp, CDNS_DP_MSA_MISC(stream_id), |
| @@ -17,7 +17,7 @@ · 16 unmodified lines | |||
| 17 | 17 | ||
| 18 | #include <drm/drm_bridge.h> | 18 | #include <drm/drm_bridge.h> |
| 19 | #include <drm/drm_connector.h> | 19 | #include <drm/drm_connector.h> |
| 20 | #include <drm/drm_dp_helper.h> | 20 | #include <drm/dp/drm_dp_helper.h> |
| 21 | 21 | ||
| 22 | struct clk; | 22 | struct clk; |
| 23 | struct device; | 23 | struct device; |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | * Author: Jagan Teki <jagan@amarulasolutions.com> | 4 | * Author: Jagan Teki <jagan@amarulasolutions.com> |
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <drm/drm_atomic_helper.h> | ||
| 7 | #include <drm/drm_of.h> | 8 | #include <drm/drm_of.h> |
| 8 | #include <drm/drm_print.h> | 9 | #include <drm/drm_print.h> |
| 9 | #include <drm/drm_mipi_dsi.h> | 10 | #include <drm/drm_mipi_dsi.h> |
| @@ -30,6 +31,7 @@ · 20 unmodified lines | |||
| 30 | struct chipone { | 31 | struct chipone { |
| 31 | struct device *dev; | 32 | struct device *dev; |
| 32 | struct drm_bridge bridge; | 33 | struct drm_bridge bridge; |
| 34 | struct drm_display_mode mode; | ||
| 33 | struct drm_bridge *panel_bridge; | 35 | struct drm_bridge *panel_bridge; |
| 34 | struct gpio_desc *enable_gpio; | 36 | struct gpio_desc *enable_gpio; |
| 35 | struct regulator *vdd1; | 37 | struct regulator *vdd1; |
| @@ -42,11 +44,6 @@ static inline struct chipone *bridge_to_chipone(struct drm_bridge *bridge) · 6 unmodified lines | |||
| 42 | return container_of(bridge, struct chipone, bridge); | 44 | return container_of(bridge, struct chipone, bridge); |
| 43 | } | 45 | } |
| 44 | 46 | ||
| 45 | static struct drm_display_mode *bridge_to_mode(struct drm_bridge *bridge) | ||
| 46 | { | ||
| 47 | return &bridge->encoder->crtc->state->adjusted_mode; | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline int chipone_dsi_write(struct chipone *icn, const void *seq, | 47 | static inline int chipone_dsi_write(struct chipone *icn, const void *seq, |
| 51 | size_t len) | 48 | size_t len) |
| 52 | { | 49 | { |
| @@ -61,10 +58,11 @@ static inline int chipone_dsi_write(struct chipone *icn, const void *seq, · 8 unmodified lines | |||
| 61 | chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \ | 58 | chipone_dsi_write(icn, d, ARRAY_SIZE(d)); \ |
| 62 | } | 59 | } |
| 63 | 60 | ||
| 64 | static void chipone_enable(struct drm_bridge *bridge) | 61 | static void chipone_atomic_enable(struct drm_bridge *bridge, |
| 62 | struct drm_bridge_state *old_bridge_state) | ||
| 65 | { | 63 | { |
| 66 | struct chipone *icn = bridge_to_chipone(bridge); | 64 | struct chipone *icn = bridge_to_chipone(bridge); |
| 67 | struct drm_display_mode *mode = bridge_to_mode(bridge); | 65 | struct drm_display_mode *mode = &icn->mode; |
| 68 | 66 | ||
| 69 | ICN6211_DSI(icn, 0x7a, 0xc1); | 67 | ICN6211_DSI(icn, 0x7a, 0xc1); |
| 70 | 68 | ||
| @@ -114,7 +112,8 @@ static void chipone_enable(struct drm_bridge *bridge) · 43 unmodified lines | |||
| 114 | usleep_range(10000, 11000); | 112 | usleep_range(10000, 11000); |
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | static void chipone_pre_enable(struct drm_bridge *bridge) | 115 | static void chipone_atomic_pre_enable(struct drm_bridge *bridge, |
| 116 | struct drm_bridge_state *old_bridge_state) | ||
| 118 | { | 117 | { |
| 119 | struct chipone *icn = bridge_to_chipone(bridge); | 118 | struct chipone *icn = bridge_to_chipone(bridge); |
| 120 | int ret; | 119 | int ret; |
| @@ -145,7 +144,8 @@ static void chipone_pre_enable(struct drm_bridge *bridge) · 24 unmodified lines | |||
| 145 | usleep_range(10000, 11000); | 144 | usleep_range(10000, 11000); |
| 146 | } | 145 | } |
| 147 | 146 | ||
| 148 | static void chipone_post_disable(struct drm_bridge *bridge) | 147 | static void chipone_atomic_post_disable(struct drm_bridge *bridge, |
| 148 | struct drm_bridge_state *old_bridge_state) | ||
| 149 | { | 149 | { |
| 150 | struct chipone *icn = bridge_to_chipone(bridge); | 150 | struct chipone *icn = bridge_to_chipone(bridge); |
| 151 | 151 | ||
| @@ -161,6 +161,15 @@ static void chipone_post_disable(struct drm_bridge *bridge) · 9 unmodified lines | |||
| 161 | gpiod_set_value(icn->enable_gpio, 0); | 161 | gpiod_set_value(icn->enable_gpio, 0); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | static void chipone_mode_set(struct drm_bridge *bridge, | ||
| 165 | const struct drm_display_mode *mode, | ||
| 166 | const struct drm_display_mode *adjusted_mode) | ||
| 167 | { | ||
| 168 | struct chipone *icn = bridge_to_chipone(bridge); | ||
| 169 | |||
| 170 | drm_mode_copy(&icn->mode, adjusted_mode); | ||
| 171 | } | ||
| 172 | |||
| 164 | static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) | 173 | static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags) |
| 165 | { | 174 | { |
| 166 | struct chipone *icn = bridge_to_chipone(bridge); | 175 | struct chipone *icn = bridge_to_chipone(bridge); |
| @@ -169,10 +178,14 @@ static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flag · 2 unmodified lines | |||
| 169 | } | 178 | } |
| 170 | 179 | ||
| 171 | static const struct drm_bridge_funcs chipone_bridge_funcs = { | 180 | static const struct drm_bridge_funcs chipone_bridge_funcs = { |
| 172 | .attach = chipone_attach, | 181 | .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
| 173 | .post_disable = chipone_post_disable, | 182 | .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
| 174 | .pre_enable = chipone_pre_enable, | 183 | .atomic_reset = drm_atomic_helper_bridge_reset, |
| 175 | .enable = chipone_enable, | 184 | .atomic_pre_enable = chipone_atomic_pre_enable, |
| 185 | .atomic_enable = chipone_atomic_enable, | ||
| 186 | .atomic_post_disable = chipone_atomic_post_disable, | ||
| 187 | .mode_set = chipone_mode_set, | ||
| 188 | .attach = chipone_attach, | ||
| 176 | }; | 189 | }; |
| 177 | 190 | ||
| 178 | static int chipone_parse_dt(struct chipone *icn) | 191 | static int chipone_parse_dt(struct chipone *icn) |
| @@ -936,9 +936,6 @@ static int it66121_probe(struct i2c_client *client, · 935 unmodified lines | |||
| 936 | return -EPROBE_DEFER; | 936 | return -EPROBE_DEFER; |
| 937 | } | 937 | } |
| 938 | 938 | ||
| 939 | if (!ctx->next_bridge) | ||
| 940 | return -EPROBE_DEFER; | ||
| 941 | |||
| 942 | i2c_set_clientdata(client, ctx); | 939 | i2c_set_clientdata(client, ctx); |
| 943 | mutex_init(&ctx->lock); | 940 | mutex_init(&ctx->lock); |
| 944 | 941 | ||
| @@ -1090,7 +1090,7 @@ static int lt9611_probe(struct i2c_client *client, · 1089 unmodified lines | |||
| 1090 | if (!lt9611) | 1090 | if (!lt9611) |
| 1091 | return -ENOMEM; | 1091 | return -ENOMEM; |
| 1092 | 1092 | ||
| 1093 | lt9611->dev = &client->dev; | 1093 | lt9611->dev = dev; |
| 1094 | lt9611->client = client; | 1094 | lt9611->client = client; |
| 1095 | lt9611->sleep = false; | 1095 | lt9611->sleep = false; |
| 1096 | 1096 | ||
| @@ -1100,7 +1100,7 @@ static int lt9611_probe(struct i2c_client *client, · 3 unmodified lines | |||
| 1100 | return PTR_ERR(lt9611->regmap); | 1100 | return PTR_ERR(lt9611->regmap); |
| 1101 | } | 1101 | } |
| 1102 | 1102 | ||
| 1103 | ret = lt9611_parse_dt(&client->dev, lt9611); | 1103 | ret = lt9611_parse_dt(dev, lt9611); |
| 1104 | if (ret) { | 1104 | if (ret) { |
| 1105 | dev_err(dev, "failed to parse device tree\n"); | 1105 | dev_err(dev, "failed to parse device tree\n"); |
| 1106 | return ret; | 1106 | return ret; |
| @@ -860,7 +860,7 @@ static int lt9611uxc_probe(struct i2c_client *client, · 859 unmodified lines | |||
| 860 | if (!lt9611uxc) | 860 | if (!lt9611uxc) |
| 861 | return -ENOMEM; | 861 | return -ENOMEM; |
| 862 | 862 | ||
| 863 | lt9611uxc->dev = &client->dev; | 863 | lt9611uxc->dev = dev; |
| 864 | lt9611uxc->client = client; | 864 | lt9611uxc->client = client; |
| 865 | mutex_init(<9611uxc->ocm_lock); | 865 | mutex_init(<9611uxc->ocm_lock); |
| 866 | 866 | ||
| @@ -870,7 +870,7 @@ static int lt9611uxc_probe(struct i2c_client *client, · 3 unmodified lines | |||
| 870 | return PTR_ERR(lt9611uxc->regmap); | 870 | return PTR_ERR(lt9611uxc->regmap); |
| 871 | } | 871 | } |
| 872 | 872 | ||
| 873 | ret = lt9611uxc_parse_dt(&client->dev, lt9611uxc); | 873 | ret = lt9611uxc_parse_dt(dev, lt9611uxc); |
| 874 | if (ret) { | 874 | if (ret) { |
| 875 | dev_err(dev, "failed to parse device tree\n"); | 875 | dev_err(dev, "failed to parse device tree\n"); |
| 876 | return ret; | 876 | return ret; |
| @@ -65,7 +65,6 @@ struct nwl_dsi_transfer { · 64 unmodified lines | |||
| 65 | struct nwl_dsi { | 65 | struct nwl_dsi { |
| 66 | struct drm_bridge bridge; | 66 | struct drm_bridge bridge; |
| 67 | struct mipi_dsi_host dsi_host; | 67 | struct mipi_dsi_host dsi_host; |
| 68 | struct drm_bridge *panel_bridge; | ||
| 69 | struct device *dev; | 68 | struct device *dev; |
| 70 | struct phy *phy; | 69 | struct phy *phy; |
| 71 | union phy_configure_opts phy_cfg; | 70 | union phy_configure_opts phy_cfg; |
| @@ -924,13 +923,11 @@ static int nwl_dsi_bridge_attach(struct drm_bridge *bridge, · 852 unmodified lines | |||
| 924 | if (IS_ERR(panel_bridge)) | 923 | if (IS_ERR(panel_bridge)) |
| 925 | return PTR_ERR(panel_bridge); | 924 | return PTR_ERR(panel_bridge); |
| 926 | } | 925 | } |
| 927 | dsi->panel_bridge = panel_bridge; | ||
| 928 | 926 | ||
| 929 | if (!dsi->panel_bridge) | 927 | if (!panel_bridge) |
| 930 | return -EPROBE_DEFER; | 928 | return -EPROBE_DEFER; |
| 931 | 929 | ||
| 932 | return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge, | 930 | return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags); |
| 933 | flags); | ||
| 934 | } | 931 | } |
| 935 | 932 | ||
| 936 | static void nwl_dsi_bridge_detach(struct drm_bridge *bridge) | 933 | static void nwl_dsi_bridge_detach(struct drm_bridge *bridge) |
| @@ -1206,6 +1203,7 @@ static int nwl_dsi_probe(struct platform_device *pdev) · 269 unmodified lines | |||
| 1206 | 1203 | ||
| 1207 | ret = nwl_dsi_select_input(dsi); | 1204 | ret = nwl_dsi_select_input(dsi); |
| 1208 | if (ret < 0) { | 1205 | if (ret < 0) { |
| 1206 | pm_runtime_disable(dev); | ||
| 1209 | mipi_dsi_host_unregister(&dsi->dsi_host); | 1207 | mipi_dsi_host_unregister(&dsi->dsi_host); |
| 1210 | return ret; | 1208 | return ret; |
| 1211 | } | 1209 | } |
| @@ -14,8 +14,8 @@ · 13 unmodified lines | |||
| 14 | #include <linux/regulator/consumer.h> | 14 | #include <linux/regulator/consumer.h> |
| 15 | 15 | ||
| 16 | #include <drm/drm_bridge.h> | 16 | #include <drm/drm_bridge.h> |
| 17 | #include <drm/drm_dp_aux_bus.h> | 17 | #include <drm/dp/drm_dp_aux_bus.h> |
| 18 | #include <drm/drm_dp_helper.h> | 18 | #include <drm/dp/drm_dp_helper.h> |
| 19 | #include <drm/drm_mipi_dsi.h> | 19 | #include <drm/drm_mipi_dsi.h> |
| 20 | #include <drm/drm_of.h> | 20 | #include <drm/drm_of.h> |
| 21 | #include <drm/drm_panel.h> | 21 | #include <drm/drm_panel.h> |
| @@ -102,6 +102,7 @@ struct ps8640 { · 80 unmodified lines | |||
| 102 | struct regulator_bulk_data supplies[2]; | 102 | struct regulator_bulk_data supplies[2]; |
| 103 | struct gpio_desc *gpio_reset; | 103 | struct gpio_desc *gpio_reset; |
| 104 | struct gpio_desc *gpio_powerdown; | 104 | struct gpio_desc *gpio_powerdown; |
| 105 | struct device_link *link; | ||
| 105 | bool pre_enabled; | 106 | bool pre_enabled; |
| 106 | }; | 107 | }; |
| 107 | 108 | ||
| @@ -456,14 +457,36 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge, · 348 unmodified lines | |||
| 456 | return ret; | 457 | return ret; |
| 457 | } | 458 | } |
| 458 | 459 | ||
| 460 | ps_bridge->link = device_link_add(bridge->dev->dev, dev, DL_FLAG_STATELESS); | ||
| 461 | if (!ps_bridge->link) { | ||
| 462 | dev_err(dev, "failed to create device link"); | ||
| 463 | ret = -EINVAL; | ||
| 464 | goto err_devlink; | ||
| 465 | } | ||
| 466 | |||
| 459 | /* Attach the panel-bridge to the dsi bridge */ | 467 | /* Attach the panel-bridge to the dsi bridge */ |
| 460 | return drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, | 468 | ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge, |
| 461 | &ps_bridge->bridge, flags); | 469 | &ps_bridge->bridge, flags); |
| 470 | if (ret) | ||
| 471 | goto err_bridge_attach; | ||
| 472 | |||
| 473 | return 0; | ||
| 474 | |||
| 475 | err_bridge_attach: | ||
| 476 | device_link_del(ps_bridge->link); | ||
| 477 | err_devlink: | ||
| 478 | drm_dp_aux_unregister(&ps_bridge->aux); | ||
| 479 | |||
| 480 | return ret; | ||
| 462 | } | 481 | } |
| 463 | 482 | ||
| 464 | static void ps8640_bridge_detach(struct drm_bridge *bridge) | 483 | static void ps8640_bridge_detach(struct drm_bridge *bridge) |
| 465 | { | 484 | { |
| 466 | drm_dp_aux_unregister(&bridge_to_ps8640(bridge)->aux); | 485 | struct ps8640 *ps_bridge = bridge_to_ps8640(bridge); |
| 486 | |||
| 487 | drm_dp_aux_unregister(&ps_bridge->aux); | ||
| 488 | if (ps_bridge->link) | ||
| 489 | device_link_del(ps_bridge->link); | ||
| 467 | } | 490 | } |
| 468 | 491 | ||
| 469 | static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, | 492 | static struct edid *ps8640_bridge_get_edid(struct drm_bridge *bridge, |
| @@ -166,10 +166,12 @@ struct sii902x { · 165 unmodified lines | |||
| 166 | struct i2c_client *i2c; | 166 | struct i2c_client *i2c; |
| 167 | struct regmap *regmap; | 167 | struct regmap *regmap; |
| 168 | struct drm_bridge bridge; | 168 | struct drm_bridge bridge; |
| 169 | struct drm_bridge *next_bridge; | ||
| 169 | struct drm_connector connector; | 170 | struct drm_connector connector; |
| 170 | struct gpio_desc *reset_gpio; | 171 | struct gpio_desc *reset_gpio; |
| 171 | struct i2c_mux_core *i2cmux; | 172 | struct i2c_mux_core *i2cmux; |
| 172 | struct regulator_bulk_data supplies[2]; | 173 | struct regulator_bulk_data supplies[2]; |
| 174 | bool sink_is_hdmi; | ||
| 173 | /* | 175 | /* |
| 174 | * Mutex protects audio and video functions from interfering | 176 | * Mutex protects audio and video functions from interfering |
| 175 | * each other, by keeping their i2c command sequences atomic. | 177 | * each other, by keeping their i2c command sequences atomic. |
| @@ -245,10 +247,8 @@ static void sii902x_reset(struct sii902x *sii902x) · 69 unmodified lines | |||
| 245 | gpiod_set_value(sii902x->reset_gpio, 0); | 247 | gpiod_set_value(sii902x->reset_gpio, 0); |
| 246 | } | 248 | } |
| 247 | 249 | ||
| 248 | static enum drm_connector_status | 250 | static enum drm_connector_status sii902x_detect(struct sii902x *sii902x) |
| 249 | sii902x_connector_detect(struct drm_connector *connector, bool force) | ||
| 250 | { | 251 | { |
| 251 | struct sii902x *sii902x = connector_to_sii902x(connector); | ||
| 252 | unsigned int status; | 252 | unsigned int status; |
| 253 | 253 | ||
| 254 | mutex_lock(&sii902x->mutex); | 254 | mutex_lock(&sii902x->mutex); |
| @@ -261,6 +261,14 @@ sii902x_connector_detect(struct drm_connector *connector, bool force) · 6 unmodified lines | |||
| 261 | connector_status_connected : connector_status_disconnected; | 261 | connector_status_connected : connector_status_disconnected; |
| 262 | } | 262 | } |
| 263 | 263 | ||
| 264 | static enum drm_connector_status | ||
| 265 | sii902x_connector_detect(struct drm_connector *connector, bool force) | ||
| 266 | { | ||
| 267 | struct sii902x *sii902x = connector_to_sii902x(connector); | ||
| 268 | |||
| 269 | return sii902x_detect(sii902x); | ||
| 270 | } | ||
| 271 | |||
| 264 | static const struct drm_connector_funcs sii902x_connector_funcs = { | 272 | static const struct drm_connector_funcs sii902x_connector_funcs = { |
| 265 | .detect = sii902x_connector_detect, | 273 | .detect = sii902x_connector_detect, |
| 266 | .fill_modes = drm_helper_probe_single_connector_modes, | 274 | .fill_modes = drm_helper_probe_single_connector_modes, |
| @@ -270,42 +278,40 @@ static const struct drm_connector_funcs sii902x_connector_funcs = { · 3 unmodified lines | |||
| 270 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, | 278 | .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, |
| 271 | }; | 279 | }; |
| 272 | 280 | ||
| 273 | static int sii902x_get_modes(struct drm_connector *connector) | 281 | static struct edid *sii902x_get_edid(struct sii902x *sii902x, |
| 282 | struct drm_connector *connector) | ||
| 274 | { | 283 | { |
| 275 | struct sii902x *sii902x = connector_to_sii902x(connector); | ||
| 276 | u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
| 277 | u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; | ||
| 278 | struct edid *edid; | 284 | struct edid *edid; |
| 279 | int num = 0, ret; | ||
| 280 | 285 | ||
| 281 | mutex_lock(&sii902x->mutex); | 286 | mutex_lock(&sii902x->mutex); |
| 282 | 287 | ||
| 283 | edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); | 288 | edid = drm_get_edid(connector, sii902x->i2cmux->adapter[0]); |
| 284 | drm_connector_update_edid_property(connector, edid); | ||
| 285 | if (edid) { | 289 | if (edid) { |
| 286 | if (drm_detect_hdmi_monitor(edid)) | 290 | if (drm_detect_hdmi_monitor(edid)) |
| 287 | output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; | 291 | sii902x->sink_is_hdmi = true; |
| 288 | 292 | else | |
| 289 | num = drm_add_edid_modes(connector, edid); | 293 | sii902x->sink_is_hdmi = false; |
| 290 | kfree(edid); | ||
| 291 | } | 294 | } |
| 292 | 295 | ||
| 293 | ret = drm_display_info_set_bus_formats(&connector->display_info, | 296 | mutex_unlock(&sii902x->mutex); |
| 294 | &bus_format, 1); | ||
| 295 | if (ret) | ||
| 296 | goto error_out; | ||
| 297 | 297 | ||
| 298 | ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | 298 | return edid; |
| 299 | SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); | 299 | } |
| 300 | if (ret) | ||
| 301 | goto error_out; | ||
| 302 | 300 | ||
| 303 | ret = num; | 301 | static int sii902x_get_modes(struct drm_connector *connector) |
| 302 | { | ||
| 303 | struct sii902x *sii902x = connector_to_sii902x(connector); | ||
| 304 | struct edid *edid; | ||
| 305 | int num = 0; | ||
| 304 | 306 | ||
| 305 | error_out: | 307 | edid = sii902x_get_edid(sii902x, connector); |
| 306 | mutex_unlock(&sii902x->mutex); | 308 | drm_connector_update_edid_property(connector, edid); |
| 309 | if (edid) { | ||
| 310 | num = drm_add_edid_modes(connector, edid); | ||
| 311 | kfree(edid); | ||
| 312 | } | ||
| 307 | 313 | ||
| 308 | return ret; | 314 | return num; |
| 309 | } | 315 | } |
| 310 | 316 | ||
| 311 | static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, | 317 | static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector, |
| @@ -354,12 +360,16 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, · 42 unmodified lines | |||
| 354 | const struct drm_display_mode *adj) | 360 | const struct drm_display_mode *adj) |
| 355 | { | 361 | { |
| 356 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | 362 | struct sii902x *sii902x = bridge_to_sii902x(bridge); |
| 363 | u8 output_mode = SII902X_SYS_CTRL_OUTPUT_DVI; | ||
| 357 | struct regmap *regmap = sii902x->regmap; | 364 | struct regmap *regmap = sii902x->regmap; |
| 358 | u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; | 365 | u8 buf[HDMI_INFOFRAME_SIZE(AVI)]; |
| 359 | struct hdmi_avi_infoframe frame; | 366 | struct hdmi_avi_infoframe frame; |
| 360 | u16 pixel_clock_10kHz = adj->clock / 10; | 367 | u16 pixel_clock_10kHz = adj->clock / 10; |
| 361 | int ret; | 368 | int ret; |
| 362 | 369 | ||
| 370 | if (sii902x->sink_is_hdmi) | ||
| 371 | output_mode = SII902X_SYS_CTRL_OUTPUT_HDMI; | ||
| 372 | |||
| 363 | buf[0] = pixel_clock_10kHz & 0xff; | 373 | buf[0] = pixel_clock_10kHz & 0xff; |
| 364 | buf[1] = pixel_clock_10kHz >> 8; | 374 | buf[1] = pixel_clock_10kHz >> 8; |
| 365 | buf[2] = drm_mode_vrefresh(adj); | 375 | buf[2] = drm_mode_vrefresh(adj); |
| @@ -375,6 +385,11 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge, · 9 unmodified lines | |||
| 375 | 385 | ||
| 376 | mutex_lock(&sii902x->mutex); | 386 | mutex_lock(&sii902x->mutex); |
| 377 | 387 | ||
| 388 | ret = regmap_update_bits(sii902x->regmap, SII902X_SYS_CTRL_DATA, | ||
| 389 | SII902X_SYS_CTRL_OUTPUT_MODE, output_mode); | ||
| 390 | if (ret) | ||
| 391 | goto out; | ||
| 392 | |||
| 378 | ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); | 393 | ret = regmap_bulk_write(regmap, SII902X_TPI_VIDEO_DATA, buf, 10); |
| 379 | if (ret) | 394 | if (ret) |
| 380 | goto out; | 395 | goto out; |
| @@ -405,13 +420,13 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge, · 24 unmodified lines | |||
| 405 | enum drm_bridge_attach_flags flags) | 420 | enum drm_bridge_attach_flags flags) |
| 406 | { | 421 | { |
| 407 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | 422 | struct sii902x *sii902x = bridge_to_sii902x(bridge); |
| 423 | u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24; | ||
| 408 | struct drm_device *drm = bridge->dev; | 424 | struct drm_device *drm = bridge->dev; |
| 409 | int ret; | 425 | int ret; |
| 410 | 426 | ||
| 411 | if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { | 427 | if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) |
| 412 | DRM_ERROR("Fix bridge driver to make connector optional!"); | 428 | return drm_bridge_attach(bridge->encoder, sii902x->next_bridge, |
| 413 | return -EINVAL; | 429 | bridge, flags); |
| 414 | } | ||
| 415 | 430 | ||
| 416 | drm_connector_helper_add(&sii902x->connector, | 431 | drm_connector_helper_add(&sii902x->connector, |
| 417 | &sii902x_connector_helper_funcs); | 432 | &sii902x_connector_helper_funcs); |
| @@ -433,16 +448,38 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge, · 15 unmodified lines | |||
| 433 | else | 448 | else |
| 434 | sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; | 449 | sii902x->connector.polled = DRM_CONNECTOR_POLL_CONNECT; |
| 435 | 450 | ||
| 451 | ret = drm_display_info_set_bus_formats(&sii902x->connector.display_info, | ||
| 452 | &bus_format, 1); | ||
| 453 | if (ret) | ||
| 454 | return ret; | ||
| 455 | |||
| 436 | drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); | 456 | drm_connector_attach_encoder(&sii902x->connector, bridge->encoder); |
| 437 | 457 | ||
| 438 | return 0; | 458 | return 0; |
| 439 | } | 459 | } |
| 440 | 460 | ||
| 461 | static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge) | ||
| 462 | { | ||
| 463 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||
| 464 | |||
| 465 | return sii902x_detect(sii902x); | ||
| 466 | } | ||
| 467 | |||
| 468 | static struct edid *sii902x_bridge_get_edid(struct drm_bridge *bridge, | ||
| 469 | struct drm_connector *connector) | ||
| 470 | { | ||
| 471 | struct sii902x *sii902x = bridge_to_sii902x(bridge); | ||
| 472 | |||
| 473 | return sii902x_get_edid(sii902x, connector); | ||
| 474 | } | ||
| 475 | |||
| 441 | static const struct drm_bridge_funcs sii902x_bridge_funcs = { | 476 | static const struct drm_bridge_funcs sii902x_bridge_funcs = { |
| 442 | .attach = sii902x_bridge_attach, | 477 | .attach = sii902x_bridge_attach, |
| 443 | .mode_set = sii902x_bridge_mode_set, | 478 | .mode_set = sii902x_bridge_mode_set, |
| 444 | .disable = sii902x_bridge_disable, | 479 | .disable = sii902x_bridge_disable, |
| 445 | .enable = sii902x_bridge_enable, | 480 | .enable = sii902x_bridge_enable, |
| 481 | .detect = sii902x_bridge_detect, | ||
| 482 | .get_edid = sii902x_bridge_get_edid, | ||
| 446 | }; | 483 | }; |
| 447 | 484 | ||
| 448 | static int sii902x_mute(struct sii902x *sii902x, bool mute) | 485 | static int sii902x_mute(struct sii902x *sii902x, bool mute) |
| @@ -829,8 +866,12 @@ static irqreturn_t sii902x_interrupt(int irq, void *data) · 380 unmodified lines | |||
| 829 | 866 | ||
| 830 | mutex_unlock(&sii902x->mutex); | 867 | mutex_unlock(&sii902x->mutex); |
| 831 | 868 | ||
| 832 | if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) | 869 | if ((status & SII902X_HOTPLUG_EVENT) && sii902x->bridge.dev) { |
| 833 | drm_helper_hpd_irq_event(sii902x->bridge.dev); | 870 | drm_helper_hpd_irq_event(sii902x->bridge.dev); |
| 871 | drm_bridge_hpd_notify(&sii902x->bridge, (status & SII902X_PLUGGED_STATUS) | ||
| 872 | ? connector_status_connected | ||
| 873 | : connector_status_disconnected); | ||
| 874 | } | ||
| 834 | 875 | ||
| 835 | return IRQ_HANDLED; | 876 | return IRQ_HANDLED; |
| 836 | } | 877 | } |
| @@ -1001,6 +1042,11 @@ static int sii902x_init(struct sii902x *sii902x) · 164 unmodified lines | |||
| 1001 | sii902x->bridge.funcs = &sii902x_bridge_funcs; | 1042 | sii902x->bridge.funcs = &sii902x_bridge_funcs; |
| 1002 | sii902x->bridge.of_node = dev->of_node; | 1043 | sii902x->bridge.of_node = dev->of_node; |
| 1003 | sii902x->bridge.timings = &default_sii902x_timings; | 1044 | sii902x->bridge.timings = &default_sii902x_timings; |
| 1045 | sii902x->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID; | ||
| 1046 | |||
| 1047 | if (sii902x->i2c->irq > 0) | ||
| 1048 | sii902x->bridge.ops |= DRM_BRIDGE_OP_HPD; | ||
| 1049 | |||
| 1004 | drm_bridge_add(&sii902x->bridge); | 1050 | drm_bridge_add(&sii902x->bridge); |
| 1005 | 1051 | ||
| 1006 | sii902x_audio_codec_init(sii902x, dev); | 1052 | sii902x_audio_codec_init(sii902x, dev); |
| @@ -1022,6 +1068,7 @@ static int sii902x_probe(struct i2c_client *client, · 15 unmodified lines | |||
| 1022 | const struct i2c_device_id *id) | 1068 | const struct i2c_device_id *id) |
| 1023 | { | 1069 | { |
| 1024 | struct device *dev = &client->dev; | 1070 | struct device *dev = &client->dev; |
| 1071 | struct device_node *endpoint; | ||
| 1025 | struct sii902x *sii902x; | 1072 | struct sii902x *sii902x; |
| 1026 | int ret; | 1073 | int ret; |
| 1027 | 1074 | ||
| @@ -1049,6 +1096,28 @@ static int sii902x_probe(struct i2c_client *client, · 21 unmodified lines | |||
| 1049 | return PTR_ERR(sii902x->reset_gpio); | 1096 | return PTR_ERR(sii902x->reset_gpio); |
| 1050 | } | 1097 | } |
| 1051 | 1098 | ||
| 1099 | endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 1, -1); | ||
| 1100 | if (endpoint) { | ||
| 1101 | struct device_node *remote = of_graph_get_remote_port_parent(endpoint); | ||
| 1102 | |||
| 1103 | of_node_put(endpoint); | ||
| 1104 | if (!remote) { | ||
| 1105 | dev_err(dev, "Endpoint in port@1 unconnected\n"); | ||
| 1106 | return -ENODEV; | ||
| 1107 | } | ||
| 1108 | |||
| 1109 | if (!of_device_is_available(remote)) { | ||
| 1110 | dev_err(dev, "port@1 remote device is disabled\n"); | ||
| 1111 | of_node_put(remote); | ||
| 1112 | return -ENODEV; | ||
| 1113 | } | ||
| 1114 | |||
| 1115 | sii902x->next_bridge = of_drm_find_bridge(remote); | ||
| 1116 | of_node_put(remote); | ||
| 1117 | if (!sii902x->next_bridge) | ||
| 1118 | return -EPROBE_DEFER; | ||
| 1119 | } | ||
| 1120 | |||
| 1052 | mutex_init(&sii902x->mutex); | 1121 | mutex_init(&sii902x->mutex); |
| 1053 | 1122 | ||
| 1054 | sii902x->supplies[0].supply = "iovcc"; | 1123 | sii902x->supplies[0].supply = "iovcc"; |
| @@ -2120,7 +2120,7 @@ static void sii8620_init_rcp_input_dev(struct sii8620 *ctx) · 2119 unmodified lines | |||
| 2120 | if (ret) { | 2120 | if (ret) { |
| 2121 | dev_err(ctx->dev, "Failed to register RC device\n"); | 2121 | dev_err(ctx->dev, "Failed to register RC device\n"); |
| 2122 | ctx->error = ret; | 2122 | ctx->error = ret; |
| 2123 | rc_free_device(ctx->rc_dev); | 2123 | rc_free_device(rc_dev); |
| 2124 | return; | 2124 | return; |
| 2125 | } | 2125 | } |
| 2126 | ctx->rc_dev = rc_dev; | 2126 | ctx->rc_dev = rc_dev; |
| @@ -2540,7 +2540,7 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, · 2539 unmodified lines | |||
| 2540 | struct drm_display_mode *mode = &crtc_state->mode; | 2540 | struct drm_display_mode *mode = &crtc_state->mode; |
| 2541 | u8 max_bpc = conn_state->max_requested_bpc; | 2541 | u8 max_bpc = conn_state->max_requested_bpc; |
| 2542 | bool is_hdmi2_sink = info->hdmi.scdc.supported || | 2542 | bool is_hdmi2_sink = info->hdmi.scdc.supported || |
| 2543 | (info->color_formats & DRM_COLOR_FORMAT_YCRCB420); | 2543 | (info->color_formats & DRM_COLOR_FORMAT_YCBCR420); |
| 2544 | u32 *output_fmts; | 2544 | u32 *output_fmts; |
| 2545 | unsigned int i = 0; | 2545 | unsigned int i = 0; |
| 2546 | 2546 | ||
| @@ -2594,36 +2594,36 @@ static u32 *dw_hdmi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge, · 47 unmodified lines | |||
| 2594 | */ | 2594 | */ |
| 2595 | 2595 | ||
| 2596 | if (max_bpc >= 16 && info->bpc == 16) { | 2596 | if (max_bpc >= 16 && info->bpc == 16) { |
| 2597 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | 2597 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) |
| 2598 | output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; | 2598 | output_fmts[i++] = MEDIA_BUS_FMT_YUV16_1X48; |
| 2599 | 2599 | ||
| 2600 | output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; | 2600 | output_fmts[i++] = MEDIA_BUS_FMT_RGB161616_1X48; |
| 2601 | } | 2601 | } |
| 2602 | 2602 | ||
| 2603 | if (max_bpc >= 12 && info->bpc >= 12) { | 2603 | if (max_bpc >= 12 && info->bpc >= 12) { |
| 2604 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | 2604 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) |
| 2605 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; | 2605 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY12_1X24; |
| 2606 | 2606 | ||
| 2607 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | 2607 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) |
| 2608 | output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; | 2608 | output_fmts[i++] = MEDIA_BUS_FMT_YUV12_1X36; |
| 2609 | 2609 | ||
| 2610 | output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; | 2610 | output_fmts[i++] = MEDIA_BUS_FMT_RGB121212_1X36; |
| 2611 | } | 2611 | } |
| 2612 | 2612 | ||
| 2613 | if (max_bpc >= 10 && info->bpc >= 10) { | 2613 | if (max_bpc >= 10 && info->bpc >= 10) { |
| 2614 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | 2614 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) |
| 2615 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; | 2615 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY10_1X20; |
| 2616 | 2616 | ||
| 2617 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | 2617 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) |
| 2618 | output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; | 2618 | output_fmts[i++] = MEDIA_BUS_FMT_YUV10_1X30; |
| 2619 | 2619 | ||
| 2620 | output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; | 2620 | output_fmts[i++] = MEDIA_BUS_FMT_RGB101010_1X30; |
| 2621 | } | 2621 | } |
| 2622 | 2622 | ||
| 2623 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB422) | 2623 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR422) |
| 2624 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; | 2624 | output_fmts[i++] = MEDIA_BUS_FMT_UYVY8_1X16; |
| 2625 | 2625 | ||
| 2626 | if (info->color_formats & DRM_COLOR_FORMAT_YCRCB444) | 2626 | if (info->color_formats & DRM_COLOR_FORMAT_YCBCR444) |
| 2627 | output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; | 2627 | output_fmts[i++] = MEDIA_BUS_FMT_YUV8_1X24; |
| 2628 | 2628 | ||
| 2629 | /* Default 8bit RGB fallback */ | 2629 | /* Default 8bit RGB fallback */ |
| @@ -871,7 +871,8 @@ static void dw_mipi_dsi_clear_err(struct dw_mipi_dsi *dsi) · 870 unmodified lines | |||
| 871 | dsi_write(dsi, DSI_INT_MSK1, 0); | 871 | dsi_write(dsi, DSI_INT_MSK1, 0); |
| 872 | } | 872 | } |
| 873 | 873 | ||
| 874 | static void dw_mipi_dsi_bridge_post_disable(struct drm_bridge *bridge) | 874 | static void dw_mipi_dsi_bridge_post_atomic_disable(struct drm_bridge *bridge, |
| 875 | struct drm_bridge_state *old_bridge_state) | ||
| 875 | { | 876 | { |
| 876 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); | 877 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
| 877 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; | 878 | const struct dw_mipi_dsi_phy_ops *phy_ops = dsi->plat_data->phy_ops; |
| @@ -978,7 +979,8 @@ static void dw_mipi_dsi_bridge_mode_set(struct drm_bridge *bridge, · 100 unmodified lines | |||
| 978 | dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); | 979 | dw_mipi_dsi_mode_set(dsi->slave, adjusted_mode); |
| 979 | } | 980 | } |
| 980 | 981 | ||
| 981 | static void dw_mipi_dsi_bridge_enable(struct drm_bridge *bridge) | 982 | static void dw_mipi_dsi_bridge_atomic_enable(struct drm_bridge *bridge, |
| 983 | struct drm_bridge_state *old_bridge_state) | ||
| 982 | { | 984 | { |
| 983 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); | 985 | struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge); |
| 984 | 986 | ||
| @@ -998,7 +1000,10 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge, · 13 unmodified lines | |||
| 998 | enum drm_mode_status mode_status = MODE_OK; | 1000 | enum drm_mode_status mode_status = MODE_OK; |
| 999 | 1001 | ||
| 1000 | if (pdata->mode_valid) | 1002 | if (pdata->mode_valid) |
| 1001 | mode_status = pdata->mode_valid(pdata->priv_data, mode); | 1003 | mode_status = pdata->mode_valid(pdata->priv_data, mode, |
| 1004 | dsi->mode_flags, | ||
| 1005 | dw_mipi_dsi_get_lanes(dsi), | ||
| 1006 | dsi->format); | ||
| 1002 | 1007 | ||
| 1003 | return mode_status; | 1008 | return mode_status; |
| 1004 | } | 1009 | } |
| @@ -1032,11 +1037,14 @@ static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge, · 27 unmodified lines | |||
| 1032 | } | 1037 | } |
| 1033 | 1038 | ||
| 1034 | static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { | 1039 | static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = { |
| 1035 | .mode_set = dw_mipi_dsi_bridge_mode_set, | 1040 | .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state, |
| 1036 | .enable = dw_mipi_dsi_bridge_enable, | 1041 | .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state, |
| 1037 | .post_disable = dw_mipi_dsi_bridge_post_disable, | 1042 | .atomic_reset = drm_atomic_helper_bridge_reset, |
| 1038 | .mode_valid = dw_mipi_dsi_bridge_mode_valid, | 1043 | .atomic_enable = dw_mipi_dsi_bridge_atomic_enable, |
| 1039 | .attach = dw_mipi_dsi_bridge_attach, | 1044 | .atomic_post_disable = dw_mipi_dsi_bridge_post_atomic_disable, |
| 1045 | .mode_set = dw_mipi_dsi_bridge_mode_set, | ||
| 1046 | .mode_valid = dw_mipi_dsi_bridge_mode_valid, | ||
| 1047 | .attach = dw_mipi_dsi_bridge_attach, | ||
| 1040 | }; | 1048 | }; |
| 1041 | 1049 | ||
| 1042 | #ifdef CONFIG_DEBUG_FS | 1050 | #ifdef CONFIG_DEBUG_FS |
| @@ -1199,6 +1207,7 @@ __dw_mipi_dsi_probe(struct platform_device *pdev, · 156 unmodified lines | |||
| 1199 | ret = mipi_dsi_host_register(&dsi->dsi_host); | 1207 | ret = mipi_dsi_host_register(&dsi->dsi_host); |
| 1200 | if (ret) { | 1208 | if (ret) { |
| 1201 | dev_err(dev, "Failed to register MIPI host: %d\n", ret); | 1209 | dev_err(dev, "Failed to register MIPI host: %d\n", ret); |
| 1210 | pm_runtime_disable(dev); | ||
| 1202 | dw_mipi_dsi_debugfs_remove(dsi); | 1211 | dw_mipi_dsi_debugfs_remove(dsi); |
| 1203 | return ERR_PTR(ret); | 1212 | return ERR_PTR(ret); |
| 1204 | } | 1213 | } |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | |||
| 27 | 27 | ||
| 28 | #include <drm/drm_atomic_helper.h> | 28 | #include <drm/drm_atomic_helper.h> |
| 29 | #include <drm/drm_bridge.h> | 29 | #include <drm/drm_bridge.h> |
| 30 | #include <drm/drm_dp_helper.h> | 30 | #include <drm/dp/drm_dp_helper.h> |
| 31 | #include <drm/drm_edid.h> | 31 | #include <drm/drm_edid.h> |
| 32 | #include <drm/drm_of.h> | 32 | #include <drm/drm_of.h> |
| 33 | #include <drm/drm_panel.h> | 33 | #include <drm/drm_panel.h> |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | #include <drm/drm_atomic_helper.h> | 22 | #include <drm/drm_atomic_helper.h> |
| 23 | #include <drm/drm_bridge.h> | 23 | #include <drm/drm_bridge.h> |
| 24 | #include <drm/drm_crtc_helper.h> | 24 | #include <drm/drm_crtc_helper.h> |
| 25 | #include <drm/drm_dp_helper.h> | 25 | #include <drm/dp/drm_dp_helper.h> |
| 26 | #include <drm/drm_mipi_dsi.h> | 26 | #include <drm/drm_mipi_dsi.h> |
| 27 | #include <drm/drm_of.h> | 27 | #include <drm/drm_of.h> |
| 28 | #include <drm/drm_panel.h> | 28 | #include <drm/drm_panel.h> |
| @@ -241,7 +241,7 @@ static inline u32 TC358775_LVCFG_PCLKDIV(uint32_t val) · 212 unmodified lines | |||
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | #define TC358775_LVCFG_LVDLINK__MASK 0x00000002 | 243 | #define TC358775_LVCFG_LVDLINK__MASK 0x00000002 |
| 244 | #define TC358775_LVCFG_LVDLINK__SHIFT 0 | 244 | #define TC358775_LVCFG_LVDLINK__SHIFT 1 |
| 245 | static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val) | 245 | static inline u32 TC358775_LVCFG_LVDLINK(uint32_t val) |
| 246 | { | 246 | { |
| 247 | return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) & | 247 | return ((val) << TC358775_LVCFG_LVDLINK__SHIFT) & |
| @@ -33,6 +33,7 @@ · 32 unmodified lines | |||
| 33 | #include <linux/of_device.h> | 33 | #include <linux/of_device.h> |
| 34 | #include <linux/of_graph.h> | 34 | #include <linux/of_graph.h> |
| 35 | #include <linux/regmap.h> | 35 | #include <linux/regmap.h> |
| 36 | #include <linux/regulator/consumer.h> | ||
| 36 | 37 | ||
| 37 | #include <drm/drm_atomic_helper.h> | 38 | #include <drm/drm_atomic_helper.h> |
| 38 | #include <drm/drm_bridge.h> | 39 | #include <drm/drm_bridge.h> |
| @@ -143,6 +144,7 @@ struct sn65dsi83 { · 104 unmodified lines | |||
| 143 | struct mipi_dsi_device *dsi; | 144 | struct mipi_dsi_device *dsi; |
| 144 | struct drm_bridge *panel_bridge; | 145 | struct drm_bridge *panel_bridge; |
| 145 | struct gpio_desc *enable_gpio; | 146 | struct gpio_desc *enable_gpio; |
| 147 | struct regulator *vcc; | ||
| 146 | int dsi_lanes; | 148 | int dsi_lanes; |
| 147 | bool lvds_dual_link; | 149 | bool lvds_dual_link; |
| 148 | bool lvds_dual_link_even_odd_swap; | 150 | bool lvds_dual_link_even_odd_swap; |
| @@ -337,6 +339,12 @@ static void sn65dsi83_atomic_enable(struct drm_bridge *bridge, · 188 unmodified lines | |||
| 337 | u16 val; | 339 | u16 val; |
| 338 | int ret; | 340 | int ret; |
| 339 | 341 | ||
| 342 | ret = regulator_enable(ctx->vcc); | ||
| 343 | if (ret) { | ||
| 344 | dev_err(ctx->dev, "Failed to enable vcc: %d\n", ret); | ||
| 345 | return; | ||
| 346 | } | ||
| 347 | |||
| 340 | /* Deassert reset */ | 348 | /* Deassert reset */ |
| 341 | gpiod_set_value(ctx->enable_gpio, 1); | 349 | gpiod_set_value(ctx->enable_gpio, 1); |
| 342 | usleep_range(1000, 1100); | 350 | usleep_range(1000, 1100); |
| @@ -486,11 +494,16 @@ static void sn65dsi83_atomic_disable(struct drm_bridge *bridge, · 143 unmodified lines | |||
| 486 | struct drm_bridge_state *old_bridge_state) | 494 | struct drm_bridge_state *old_bridge_state) |
| 487 | { | 495 | { |
| 488 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); | 496 | struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge); |
| 497 | int ret; | ||
| 489 | 498 | ||
| 490 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ | 499 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ |
| 491 | gpiod_set_value(ctx->enable_gpio, 0); | 500 | gpiod_set_value(ctx->enable_gpio, 0); |
| 492 | usleep_range(10000, 11000); | 501 | usleep_range(10000, 11000); |
| 493 | 502 | ||
| 503 | ret = regulator_disable(ctx->vcc); | ||
| 504 | if (ret) | ||
| 505 | dev_err(ctx->dev, "Failed to disable vcc: %d\n", ret); | ||
| 506 | |||
| 494 | regcache_mark_dirty(ctx->regmap); | 507 | regcache_mark_dirty(ctx->regmap); |
| 495 | } | 508 | } |
| 496 | 509 | ||
| @@ -560,10 +573,14 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) · 63 unmodified lines | |||
| 560 | ctx->host_node = of_graph_get_remote_port_parent(endpoint); | 573 | ctx->host_node = of_graph_get_remote_port_parent(endpoint); |
| 561 | of_node_put(endpoint); | 574 | of_node_put(endpoint); |
| 562 | 575 | ||
| 563 | if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) | 576 | if (ctx->dsi_lanes < 0 || ctx->dsi_lanes > 4) { |
| 564 | return -EINVAL; | 577 | ret = -EINVAL; |
| 565 | if (!ctx->host_node) | 578 | goto err_put_node; |
| 566 | return -ENODEV; | 579 | } |
| 580 | if (!ctx->host_node) { | ||
| 581 | ret = -ENODEV; | ||
| 582 | goto err_put_node; | ||
| 583 | } | ||
| 567 | 584 | ||
| 568 | ctx->lvds_dual_link = false; | 585 | ctx->lvds_dual_link = false; |
| 569 | ctx->lvds_dual_link_even_odd_swap = false; | 586 | ctx->lvds_dual_link_even_odd_swap = false; |
| @@ -590,16 +607,27 @@ static int sn65dsi83_parse_dt(struct sn65dsi83 *ctx, enum sn65dsi83_model model) · 20 unmodified lines | |||
| 590 | 607 | ||
| 591 | ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge); | 608 | ret = drm_of_find_panel_or_bridge(dev->of_node, 2, 0, &panel, &panel_bridge); |
| 592 | if (ret < 0) | 609 | if (ret < 0) |
| 593 | return ret; | 610 | goto err_put_node; |
| 594 | if (panel) { | 611 | if (panel) { |
| 595 | panel_bridge = devm_drm_panel_bridge_add(dev, panel); | 612 | panel_bridge = devm_drm_panel_bridge_add(dev, panel); |
| 596 | if (IS_ERR(panel_bridge)) | 613 | if (IS_ERR(panel_bridge)) { |
| 597 | return PTR_ERR(panel_bridge); | 614 | ret = PTR_ERR(panel_bridge); |
| 615 | goto err_put_node; | ||
| 616 | } | ||
| 598 | } | 617 | } |
| 599 | 618 | ||
| 600 | ctx->panel_bridge = panel_bridge; | 619 | ctx->panel_bridge = panel_bridge; |
| 601 | 620 | ||
| 621 | ctx->vcc = devm_regulator_get(dev, "vcc"); | ||
| 622 | if (IS_ERR(ctx->vcc)) | ||
| 623 | return dev_err_probe(dev, PTR_ERR(ctx->vcc), | ||
| 624 | "Failed to get supply 'vcc'\n"); | ||
| 625 | |||
| 602 | return 0; | 626 | return 0; |
| 627 | |||
| 628 | err_put_node: | ||
| 629 | of_node_put(ctx->host_node); | ||
| 630 | return ret; | ||
| 603 | } | 631 | } |
| 604 | 632 | ||
| 605 | static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) | 633 | static int sn65dsi83_host_attach(struct sn65dsi83 *ctx) |
| @@ -662,7 +690,8 @@ static int sn65dsi83_probe(struct i2c_client *client, · 56 unmodified lines | |||
| 662 | } | 690 | } |
| 663 | 691 | ||
| 664 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ | 692 | /* Put the chip in reset, pull EN line low, and assure 10ms reset low timing. */ |
| 665 | ctx->enable_gpio = devm_gpiod_get(ctx->dev, "enable", GPIOD_OUT_LOW); | 693 | ctx->enable_gpio = devm_gpiod_get_optional(ctx->dev, "enable", |
| 694 | GPIOD_OUT_LOW); | ||
| 666 | if (IS_ERR(ctx->enable_gpio)) | 695 | if (IS_ERR(ctx->enable_gpio)) |
| 667 | return PTR_ERR(ctx->enable_gpio); | 696 | return PTR_ERR(ctx->enable_gpio); |
| 668 | 697 | ||
| @@ -673,8 +702,10 @@ static int sn65dsi83_probe(struct i2c_client *client, · 4 unmodified lines | |||
| 673 | return ret; | 702 | return ret; |
| 674 | 703 | ||
| 675 | ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config); | 704 | ctx->regmap = devm_regmap_init_i2c(client, &sn65dsi83_regmap_config); |
| 676 | if (IS_ERR(ctx->regmap)) | 705 | if (IS_ERR(ctx->regmap)) { |
| 677 | return PTR_ERR(ctx->regmap); | 706 | ret = PTR_ERR(ctx->regmap); |
| 707 | goto err_put_node; | ||
| 708 | } | ||
| 678 | 709 | ||
| 679 | dev_set_drvdata(dev, ctx); | 710 | dev_set_drvdata(dev, ctx); |
| 680 | i2c_set_clientdata(client, ctx); | 711 | i2c_set_clientdata(client, ctx); |
| @@ -691,6 +722,8 @@ static int sn65dsi83_probe(struct i2c_client *client, · 10 unmodified lines | |||
| 691 | 722 | ||
| 692 | err_remove_bridge: | 723 | err_remove_bridge: |
| 693 | drm_bridge_remove(&ctx->bridge); | 724 | drm_bridge_remove(&ctx->bridge); |
| 725 | err_put_node: | ||
| 726 | of_node_put(ctx->host_node); | ||
| 694 | return ret; | 727 | return ret; |
| 695 | } | 728 | } |
| 696 | 729 | ||
| @@ -26,8 +26,8 @@ · 25 unmodified lines | |||
| 26 | #include <drm/drm_atomic.h> | 26 | #include <drm/drm_atomic.h> |
| 27 | #include <drm/drm_atomic_helper.h> | 27 | #include <drm/drm_atomic_helper.h> |
| 28 | #include <drm/drm_bridge.h> | 28 | #include <drm/drm_bridge.h> |
| 29 | #include <drm/drm_dp_aux_bus.h> | 29 | #include <drm/dp/drm_dp_aux_bus.h> |
| 30 | #include <drm/drm_dp_helper.h> | 30 | #include <drm/dp/drm_dp_helper.h> |
| 31 | #include <drm/drm_mipi_dsi.h> | 31 | #include <drm/drm_mipi_dsi.h> |
| 32 | #include <drm/drm_of.h> | 32 | #include <drm/drm_of.h> |
| 33 | #include <drm/drm_panel.h> | 33 | #include <drm/drm_panel.h> |
| @@ -0,0 +1,9 @@ | |||
| 1 | # SPDX-License-Identifier: MIT | ||
| 2 | |||
| 3 | obj-$(CONFIG_DRM_DP_AUX_BUS) += drm_dp_aux_bus.o | ||
| 4 | |||
| 5 | drm_dp_helper-y := drm_dp.o drm_dp_dual_mode_helper.o drm_dp_helper_mod.o drm_dp_mst_topology.o | ||
| 6 | drm_dp_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o | ||
| 7 | drm_dp_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o | ||
| 8 | |||
| 9 | obj-$(CONFIG_DRM_DP_HELPER) += drm_dp_helper.o | ||
| @@ -29,13 +29,13 @@ · 28 unmodified lines | |||
| 29 | #include <linux/sched.h> | 29 | #include <linux/sched.h> |
| 30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
| 31 | 31 | ||
| 32 | #include <drm/drm_dp_helper.h> | 32 | #include <drm/dp/drm_dp_helper.h> |
| 33 | #include <drm/drm_print.h> | 33 | #include <drm/drm_print.h> |
| 34 | #include <drm/drm_vblank.h> | 34 | #include <drm/drm_vblank.h> |
| 35 | #include <drm/drm_dp_mst_helper.h> | 35 | #include <drm/dp/drm_dp_mst_helper.h> |
| 36 | #include <drm/drm_panel.h> | 36 | #include <drm/drm_panel.h> |
| 37 | 37 | ||
| 38 | #include "drm_crtc_helper_internal.h" | 38 | #include "drm_dp_helper_internal.h" |
| 39 | 39 | ||
| 40 | struct dp_aux_backlight { | 40 | struct dp_aux_backlight { |
| 41 | struct backlight_device *base; | 41 | struct backlight_device *base; |
| @@ -19,8 +19,8 @@ · 18 unmodified lines | |||
| 19 | #include <linux/pm_domain.h> | 19 | #include <linux/pm_domain.h> |
| 20 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
| 21 | 21 | ||
| 22 | #include <drm/drm_dp_aux_bus.h> | 22 | #include <drm/dp/drm_dp_aux_bus.h> |
| 23 | #include <drm/drm_dp_helper.h> | 23 | #include <drm/dp/drm_dp_helper.h> |
| 24 | 24 | ||
| 25 | /** | 25 | /** |
| 26 | * dp_aux_ep_match() - The match function for the dp_aux_bus. | 26 | * dp_aux_ep_match() - The match function for the dp_aux_bus. |
| @@ -36,11 +36,11 @@ · 35 unmodified lines | |||
| 36 | #include <linux/uio.h> | 36 | #include <linux/uio.h> |
| 37 | 37 | ||
| 38 | #include <drm/drm_crtc.h> | 38 | #include <drm/drm_crtc.h> |
| 39 | #include <drm/drm_dp_helper.h> | 39 | #include <drm/dp/drm_dp_helper.h> |
| 40 | #include <drm/drm_dp_mst_helper.h> | 40 | #include <drm/dp/drm_dp_mst_helper.h> |
| 41 | #include <drm/drm_print.h> | 41 | #include <drm/drm_print.h> |
| 42 | 42 | ||
| 43 | #include "drm_crtc_helper_internal.h" | 43 | #include "drm_dp_helper_internal.h" |
| 44 | 44 | ||
| 45 | struct drm_dp_aux_dev { | 45 | struct drm_dp_aux_dev { |
| 46 | unsigned index; | 46 | unsigned index; |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | #include <drm/drm_connector.h> | 14 | #include <drm/drm_connector.h> |
| 15 | #include <drm/drm_device.h> | 15 | #include <drm/drm_device.h> |
| 16 | #include <drm/drm_dp_helper.h> | 16 | #include <drm/dp/drm_dp_helper.h> |
| 17 | 17 | ||
| 18 | /* | 18 | /* |
| 19 | * Unfortunately it turns out that we have a chicken-and-egg situation | 19 | * Unfortunately it turns out that we have a chicken-and-egg situation |
| @@ -28,7 +28,7 @@ · 27 unmodified lines | |||
| 28 | #include <linux/string.h> | 28 | #include <linux/string.h> |
| 29 | 29 | ||
| 30 | #include <drm/drm_device.h> | 30 | #include <drm/drm_device.h> |
| 31 | #include <drm/drm_dp_dual_mode_helper.h> | 31 | #include <drm/dp/drm_dp_dual_mode_helper.h> |
| 32 | #include <drm/drm_print.h> | 32 | #include <drm/drm_print.h> |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| @@ -0,0 +1,33 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | |||
| 3 | #ifndef DRM_DP_HELPER_INTERNAL_H | ||
| 4 | #define DRM_DP_HELPER_INTERNAL_H | ||
| 5 | |||
| 6 | struct drm_dp_aux; | ||
| 7 | |||
| 8 | #ifdef CONFIG_DRM_DP_AUX_CHARDEV | ||
| 9 | int drm_dp_aux_dev_init(void); | ||
| 10 | void drm_dp_aux_dev_exit(void); | ||
| 11 | int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); | ||
| 12 | void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); | ||
| 13 | #else | ||
| 14 | static inline int drm_dp_aux_dev_init(void) | ||
| 15 | { | ||
| 16 | return 0; | ||
| 17 | } | ||
| 18 | |||
| 19 | static inline void drm_dp_aux_dev_exit(void) | ||
| 20 | { | ||
| 21 | } | ||
| 22 | |||
| 23 | static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) | ||
| 24 | { | ||
| 25 | return 0; | ||
| 26 | } | ||
| 27 | |||
| 28 | static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) | ||
| 29 | { | ||
| 30 | } | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #endif | ||
| @@ -0,0 +1,22 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | |||
| 3 | #include <linux/module.h> | ||
| 4 | |||
| 5 | #include "drm_dp_helper_internal.h" | ||
| 6 | |||
| 7 | MODULE_DESCRIPTION("DRM DisplayPort helper"); | ||
| 8 | MODULE_LICENSE("GPL and additional rights"); | ||
| 9 | |||
| 10 | static int __init drm_dp_helper_module_init(void) | ||
| 11 | { | ||
| 12 | return drm_dp_aux_dev_init(); | ||
| 13 | } | ||
| 14 | |||
| 15 | static void __exit drm_dp_helper_module_exit(void) | ||
| 16 | { | ||
| 17 | /* Call exit functions from specific dp helpers here */ | ||
| 18 | drm_dp_aux_dev_exit(); | ||
| 19 | } | ||
| 20 | |||
| 21 | module_init(drm_dp_helper_module_init); | ||
| 22 | module_exit(drm_dp_helper_module_exit); | ||
| @@ -38,14 +38,14 @@ · 37 unmodified lines | |||
| 38 | #include <linux/math64.h> | 38 | #include <linux/math64.h> |
| 39 | #endif | 39 | #endif |
| 40 | 40 | ||
| 41 | #include <drm/dp/drm_dp_mst_helper.h> | ||
| 41 | #include <drm/drm_atomic.h> | 42 | #include <drm/drm_atomic.h> |
| 42 | #include <drm/drm_atomic_helper.h> | 43 | #include <drm/drm_atomic_helper.h> |
| 43 | #include <drm/drm_dp_mst_helper.h> | ||
| 44 | #include <drm/drm_drv.h> | 44 | #include <drm/drm_drv.h> |
| 45 | #include <drm/drm_print.h> | 45 | #include <drm/drm_print.h> |
| 46 | #include <drm/drm_probe_helper.h> | 46 | #include <drm/drm_probe_helper.h> |
| 47 | 47 | ||
| 48 | #include "drm_crtc_helper_internal.h" | 48 | #include "drm_dp_helper_internal.h" |
| 49 | #include "drm_dp_mst_topology_internal.h" | 49 | #include "drm_dp_mst_topology_internal.h" |
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| @@ -4196,7 +4196,7 @@ int drm_dp_mst_hpd_irq(struct drm_dp_mst_topology_mgr *mgr, u8 *esi, bool *handl · 4144 unmodified lines | |||
| 4196 | int ret = 0; | 4196 | int ret = 0; |
| 4197 | int sc; | 4197 | int sc; |
| 4198 | *handled = false; | 4198 | *handled = false; |
| 4199 | sc = esi[0] & 0x3f; | 4199 | sc = DP_GET_SINK_COUNT(esi[0]); |
| 4200 | 4200 | ||
| 4201 | if (sc != mgr->sink_count) { | 4201 | if (sc != mgr->sink_count) { |
| 4202 | mgr->sink_count = sc; | 4202 | mgr->sink_count = sc; |
| @@ -4811,7 +4811,7 @@ static void drm_dp_mst_dump_mstb(struct seq_file *m, · 608 unmodified lines | |||
| 4811 | 4811 | ||
| 4812 | seq_printf(m, "%smstb - [%p]: num_ports: %d\n", prefix, mstb, mstb->num_ports); | 4812 | seq_printf(m, "%smstb - [%p]: num_ports: %d\n", prefix, mstb, mstb->num_ports); |
| 4813 | list_for_each_entry(port, &mstb->ports, next) { | 4813 | list_for_each_entry(port, &mstb->ports, next) { |
| 4814 | seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n", | 4814 | seq_printf(m, "%sport %d - [%p] (%s - %s): ddps: %d, ldps: %d, sdp: %d/%d, fec: %s, conn: %p\n", |
| 4815 | prefix, | 4815 | prefix, |
| 4816 | port->port_num, | 4816 | port->port_num, |
| 4817 | port, | 4817 | port, |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #ifndef _DRM_DP_MST_HELPER_INTERNAL_H_ | 10 | #ifndef _DRM_DP_MST_HELPER_INTERNAL_H_ |
| 11 | #define _DRM_DP_MST_HELPER_INTERNAL_H_ | 11 | #define _DRM_DP_MST_HELPER_INTERNAL_H_ |
| 12 | 12 | ||
| 13 | #include <drm/drm_dp_mst_helper.h> | 13 | #include <drm/dp/drm_dp_mst_helper.h> |
| 14 | 14 | ||
| 15 | void | 15 | void |
| 16 | drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req, | 16 | drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req, |
| @@ -0,0 +1,535 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | /* | ||
| 3 | * Copyright © 2021 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kmemleak.h> | ||
| 7 | #include <linux/module.h> | ||
| 8 | #include <linux/sizes.h> | ||
| 9 | |||
| 10 | #include <drm/drm_buddy.h> | ||
| 11 | |||
| 12 | static struct kmem_cache *slab_blocks; | ||
| 13 | |||
| 14 | static struct drm_buddy_block *drm_block_alloc(struct drm_buddy *mm, | ||
| 15 | struct drm_buddy_block *parent, | ||
| 16 | unsigned int order, | ||
| 17 | u64 offset) | ||
| 18 | { | ||
| 19 | struct drm_buddy_block *block; | ||
| 20 | |||
| 21 | BUG_ON(order > DRM_BUDDY_MAX_ORDER); | ||
| 22 | |||
| 23 | block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); | ||
| 24 | if (!block) | ||
| 25 | return NULL; | ||
| 26 | |||
| 27 | block->header = offset; | ||
| 28 | block->header |= order; | ||
| 29 | block->parent = parent; | ||
| 30 | |||
| 31 | BUG_ON(block->header & DRM_BUDDY_HEADER_UNUSED); | ||
| 32 | return block; | ||
| 33 | } | ||
| 34 | |||
| 35 | static void drm_block_free(struct drm_buddy *mm, | ||
| 36 | struct drm_buddy_block *block) | ||
| 37 | { | ||
| 38 | kmem_cache_free(slab_blocks, block); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void mark_allocated(struct drm_buddy_block *block) | ||
| 42 | { | ||
| 43 | block->header &= ~DRM_BUDDY_HEADER_STATE; | ||
| 44 | block->header |= DRM_BUDDY_ALLOCATED; | ||
| 45 | |||
| 46 | list_del(&block->link); | ||
| 47 | } | ||
| 48 | |||
| 49 | static void mark_free(struct drm_buddy *mm, | ||
| 50 | struct drm_buddy_block *block) | ||
| 51 | { | ||
| 52 | block->header &= ~DRM_BUDDY_HEADER_STATE; | ||
| 53 | block->header |= DRM_BUDDY_FREE; | ||
| 54 | |||
| 55 | list_add(&block->link, | ||
| 56 | &mm->free_list[drm_buddy_block_order(block)]); | ||
| 57 | } | ||
| 58 | |||
| 59 | static void mark_split(struct drm_buddy_block *block) | ||
| 60 | { | ||
| 61 | block->header &= ~DRM_BUDDY_HEADER_STATE; | ||
| 62 | block->header |= DRM_BUDDY_SPLIT; | ||
| 63 | |||
| 64 | list_del(&block->link); | ||
| 65 | } | ||
| 66 | |||
| 67 | /** | ||
| 68 | * drm_buddy_init - init memory manager | ||
| 69 | * | ||
| 70 | * @mm: DRM buddy manager to initialize | ||
| 71 | * @size: size in bytes to manage | ||
| 72 | * @chunk_size: minimum page size in bytes for our allocations | ||
| 73 | * | ||
| 74 | * Initializes the memory manager and its resources. | ||
| 75 | * | ||
| 76 | * Returns: | ||
| 77 | * 0 on success, error code on failure. | ||
| 78 | */ | ||
| 79 | int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size) | ||
| 80 | { | ||
| 81 | unsigned int i; | ||
| 82 | u64 offset; | ||
| 83 | |||
| 84 | if (size < chunk_size) | ||
| 85 | return -EINVAL; | ||
| 86 | |||
| 87 | if (chunk_size < PAGE_SIZE) | ||
| 88 | return -EINVAL; | ||
| 89 | |||
| 90 | if (!is_power_of_2(chunk_size)) | ||
| 91 | return -EINVAL; | ||
| 92 | |||
| 93 | size = round_down(size, chunk_size); | ||
| 94 | |||
| 95 | mm->size = size; | ||
| 96 | mm->avail = size; | ||
| 97 | mm->chunk_size = chunk_size; | ||
| 98 | mm->max_order = ilog2(size) - ilog2(chunk_size); | ||
| 99 | |||
| 100 | BUG_ON(mm->max_order > DRM_BUDDY_MAX_ORDER); | ||
| 101 | |||
| 102 | mm->free_list = kmalloc_array(mm->max_order + 1, | ||
| 103 | sizeof(struct list_head), | ||
| 104 | GFP_KERNEL); | ||
| 105 | if (!mm->free_list) | ||
| 106 | return -ENOMEM; | ||
| 107 | |||
| 108 | for (i = 0; i <= mm->max_order; ++i) | ||
| 109 | INIT_LIST_HEAD(&mm->free_list[i]); | ||
| 110 | |||
| 111 | mm->n_roots = hweight64(size); | ||
| 112 | |||
| 113 | mm->roots = kmalloc_array(mm->n_roots, | ||
| 114 | sizeof(struct drm_buddy_block *), | ||
| 115 | GFP_KERNEL); | ||
| 116 | if (!mm->roots) | ||
| 117 | goto out_free_list; | ||
| 118 | |||
| 119 | offset = 0; | ||
| 120 | i = 0; | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Split into power-of-two blocks, in case we are given a size that is | ||
| 124 | * not itself a power-of-two. | ||
| 125 | */ | ||
| 126 | do { | ||
| 127 | struct drm_buddy_block *root; | ||
| 128 | unsigned int order; | ||
| 129 | u64 root_size; | ||
| 130 | |||
| 131 | root_size = rounddown_pow_of_two(size); | ||
| 132 | order = ilog2(root_size) - ilog2(chunk_size); | ||
| 133 | |||
| 134 | root = drm_block_alloc(mm, NULL, order, offset); | ||
| 135 | if (!root) | ||
| 136 | goto out_free_roots; | ||
| 137 | |||
| 138 | mark_free(mm, root); | ||
| 139 | |||
| 140 | BUG_ON(i > mm->max_order); | ||
| 141 | BUG_ON(drm_buddy_block_size(mm, root) < chunk_size); | ||
| 142 | |||
| 143 | mm->roots[i] = root; | ||
| 144 | |||
| 145 | offset += root_size; | ||
| 146 | size -= root_size; | ||
| 147 | i++; | ||
| 148 | } while (size); | ||
| 149 | |||
| 150 | return 0; | ||
| 151 | |||
| 152 | out_free_roots: | ||
| 153 | while (i--) | ||
| 154 | drm_block_free(mm, mm->roots[i]); | ||
| 155 | kfree(mm->roots); | ||
| 156 | out_free_list: | ||
| 157 | kfree(mm->free_list); | ||
| 158 | return -ENOMEM; | ||
| 159 | } | ||
| 160 | EXPORT_SYMBOL(drm_buddy_init); | ||
| 161 | |||
| 162 | /** | ||
| 163 | * drm_buddy_fini - tear down the memory manager | ||
| 164 | * | ||
| 165 | * @mm: DRM buddy manager to free | ||
| 166 | * | ||
| 167 | * Cleanup memory manager resources and the freelist | ||
| 168 | */ | ||
| 169 | void drm_buddy_fini(struct drm_buddy *mm) | ||
| 170 | { | ||
| 171 | int i; | ||
| 172 | |||
| 173 | for (i = 0; i < mm->n_roots; ++i) { | ||
| 174 | WARN_ON(!drm_buddy_block_is_free(mm->roots[i])); | ||
| 175 | drm_block_free(mm, mm->roots[i]); | ||
| 176 | } | ||
| 177 | |||
| 178 | WARN_ON(mm->avail != mm->size); | ||
| 179 | |||
| 180 | kfree(mm->roots); | ||
| 181 | kfree(mm->free_list); | ||
| 182 | } | ||
| 183 | EXPORT_SYMBOL(drm_buddy_fini); | ||
| 184 | |||
| 185 | static int split_block(struct drm_buddy *mm, | ||
| 186 | struct drm_buddy_block *block) | ||
| 187 | { | ||
| 188 | unsigned int block_order = drm_buddy_block_order(block) - 1; | ||
| 189 | u64 offset = drm_buddy_block_offset(block); | ||
| 190 | |||
| 191 | BUG_ON(!drm_buddy_block_is_free(block)); | ||
| 192 | BUG_ON(!drm_buddy_block_order(block)); | ||
| 193 | |||
| 194 | block->left = drm_block_alloc(mm, block, block_order, offset); | ||
| 195 | if (!block->left) | ||
| 196 | return -ENOMEM; | ||
| 197 | |||
| 198 | block->right = drm_block_alloc(mm, block, block_order, | ||
| 199 | offset + (mm->chunk_size << block_order)); | ||
| 200 | if (!block->right) { | ||
| 201 | drm_block_free(mm, block->left); | ||
| 202 | return -ENOMEM; | ||
| 203 | } | ||
| 204 | |||
| 205 | mark_free(mm, block->left); | ||
| 206 | mark_free(mm, block->right); | ||
| 207 | |||
| 208 | mark_split(block); | ||
| 209 | |||
| 210 | return 0; | ||
| 211 | } | ||
| 212 | |||
| 213 | static struct drm_buddy_block * | ||
| 214 | get_buddy(struct drm_buddy_block *block) | ||
| 215 | { | ||
| 216 | struct drm_buddy_block *parent; | ||
| 217 | |||
| 218 | parent = block->parent; | ||
| 219 | if (!parent) | ||
| 220 | return NULL; | ||
| 221 | |||
| 222 | if (parent->left == block) | ||
| 223 | return parent->right; | ||
| 224 | |||
| 225 | return parent->left; | ||
| 226 | } | ||
| 227 | |||
| 228 | static void __drm_buddy_free(struct drm_buddy *mm, | ||
| 229 | struct drm_buddy_block *block) | ||
| 230 | { | ||
| 231 | struct drm_buddy_block *parent; | ||
| 232 | |||
| 233 | while ((parent = block->parent)) { | ||
| 234 | struct drm_buddy_block *buddy; | ||
| 235 | |||
| 236 | buddy = get_buddy(block); | ||
| 237 | |||
| 238 | if (!drm_buddy_block_is_free(buddy)) | ||
| 239 | break; | ||
| 240 | |||
| 241 | list_del(&buddy->link); | ||
| 242 | |||
| 243 | drm_block_free(mm, block); | ||
| 244 | drm_block_free(mm, buddy); | ||
| 245 | |||
| 246 | block = parent; | ||
| 247 | } | ||
| 248 | |||
| 249 | mark_free(mm, block); | ||
| 250 | } | ||
| 251 | |||
| 252 | /** | ||
| 253 | * drm_buddy_free_block - free a block | ||
| 254 | * | ||
| 255 | * @mm: DRM buddy manager | ||
| 256 | * @block: block to be freed | ||
| 257 | */ | ||
| 258 | void drm_buddy_free_block(struct drm_buddy *mm, | ||
| 259 | struct drm_buddy_block *block) | ||
| 260 | { | ||
| 261 | BUG_ON(!drm_buddy_block_is_allocated(block)); | ||
| 262 | mm->avail += drm_buddy_block_size(mm, block); | ||
| 263 | __drm_buddy_free(mm, block); | ||
| 264 | } | ||
| 265 | EXPORT_SYMBOL(drm_buddy_free_block); | ||
| 266 | |||
| 267 | /** | ||
| 268 | * drm_buddy_free_list - free blocks | ||
| 269 | * | ||
| 270 | * @mm: DRM buddy manager | ||
| 271 | * @objects: input list head to free blocks | ||
| 272 | */ | ||
| 273 | void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects) | ||
| 274 | { | ||
| 275 | struct drm_buddy_block *block, *on; | ||
| 276 | |||
| 277 | list_for_each_entry_safe(block, on, objects, link) { | ||
| 278 | drm_buddy_free_block(mm, block); | ||
| 279 | cond_resched(); | ||
| 280 | } | ||
| 281 | INIT_LIST_HEAD(objects); | ||
| 282 | } | ||
| 283 | EXPORT_SYMBOL(drm_buddy_free_list); | ||
| 284 | |||
| 285 | /** | ||
| 286 | * drm_buddy_alloc_blocks - allocate power-of-two blocks | ||
| 287 | * | ||
| 288 | * @mm: DRM buddy manager to allocate from | ||
| 289 | * @order: size of the allocation | ||
| 290 | * | ||
| 291 | * The order value here translates to: | ||
| 292 | * | ||
| 293 | * 0 = 2^0 * mm->chunk_size | ||
| 294 | * 1 = 2^1 * mm->chunk_size | ||
| 295 | * 2 = 2^2 * mm->chunk_size | ||
| 296 | * | ||
| 297 | * Returns: | ||
| 298 | * allocated ptr to the &drm_buddy_block on success | ||
| 299 | */ | ||
| 300 | struct drm_buddy_block * | ||
| 301 | drm_buddy_alloc_blocks(struct drm_buddy *mm, unsigned int order) | ||
| 302 | { | ||
| 303 | struct drm_buddy_block *block = NULL; | ||
| 304 | unsigned int i; | ||
| 305 | int err; | ||
| 306 | |||
| 307 | for (i = order; i <= mm->max_order; ++i) { | ||
| 308 | block = list_first_entry_or_null(&mm->free_list[i], | ||
| 309 | struct drm_buddy_block, | ||
| 310 | link); | ||
| 311 | if (block) | ||
| 312 | break; | ||
| 313 | } | ||
| 314 | |||
| 315 | if (!block) | ||
| 316 | return ERR_PTR(-ENOSPC); | ||
| 317 | |||
| 318 | BUG_ON(!drm_buddy_block_is_free(block)); | ||
| 319 | |||
| 320 | while (i != order) { | ||
| 321 | err = split_block(mm, block); | ||
| 322 | if (unlikely(err)) | ||
| 323 | goto out_free; | ||
| 324 | |||
| 325 | /* Go low */ | ||
| 326 | block = block->left; | ||
| 327 | i--; | ||
| 328 | } | ||
| 329 | |||
| 330 | mark_allocated(block); | ||
| 331 | mm->avail -= drm_buddy_block_size(mm, block); | ||
| 332 | kmemleak_update_trace(block); | ||
| 333 | return block; | ||
| 334 | |||
| 335 | out_free: | ||
| 336 | if (i != order) | ||
| 337 | __drm_buddy_free(mm, block); | ||
| 338 | return ERR_PTR(err); | ||
| 339 | } | ||
| 340 | EXPORT_SYMBOL(drm_buddy_alloc_blocks); | ||
| 341 | |||
| 342 | static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) | ||
| 343 | { | ||
| 344 | return s1 <= e2 && e1 >= s2; | ||
| 345 | } | ||
| 346 | |||
| 347 | static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) | ||
| 348 | { | ||
| 349 | return s1 <= s2 && e1 >= e2; | ||
| 350 | } | ||
| 351 | |||
| 352 | /** | ||
| 353 | * drm_buddy_alloc_range - allocate range | ||
| 354 | * | ||
| 355 | * @mm: DRM buddy manager to allocate from | ||
| 356 | * @blocks: output list head to add allocated blocks | ||
| 357 | * @start: start of the allowed range for this block | ||
| 358 | * @size: size of the allocation | ||
| 359 | * | ||
| 360 | * Intended for pre-allocating portions of the address space, for example to | ||
| 361 | * reserve a block for the initial framebuffer or similar, hence the expectation | ||
| 362 | * here is that drm_buddy_alloc_blocks() is still the main vehicle for | ||
| 363 | * allocations, so if that's not the case then the drm_mm range allocator is | ||
| 364 | * probably a much better fit, and so you should probably go use that instead. | ||
| 365 | * | ||
| 366 | * Note that it's safe to chain together multiple alloc_ranges | ||
| 367 | * with the same blocks list | ||
| 368 | * | ||
| 369 | * Returns: | ||
| 370 | * 0 on success, error code on failure. | ||
| 371 | */ | ||
| 372 | int drm_buddy_alloc_range(struct drm_buddy *mm, | ||
| 373 | struct list_head *blocks, | ||
| 374 | u64 start, u64 size) | ||
| 375 | { | ||
| 376 | struct drm_buddy_block *block; | ||
| 377 | struct drm_buddy_block *buddy; | ||
| 378 | LIST_HEAD(allocated); | ||
| 379 | LIST_HEAD(dfs); | ||
| 380 | u64 end; | ||
| 381 | int err; | ||
| 382 | int i; | ||
| 383 | |||
| 384 | if (size < mm->chunk_size) | ||
| 385 | return -EINVAL; | ||
| 386 | |||
| 387 | if (!IS_ALIGNED(size | start, mm->chunk_size)) | ||
| 388 | return -EINVAL; | ||
| 389 | |||
| 390 | if (range_overflows(start, size, mm->size)) | ||
| 391 | return -EINVAL; | ||
| 392 | |||
| 393 | for (i = 0; i < mm->n_roots; ++i) | ||
| 394 | list_add_tail(&mm->roots[i]->tmp_link, &dfs); | ||
| 395 | |||
| 396 | end = start + size - 1; | ||
| 397 | |||
| 398 | do { | ||
| 399 | u64 block_start; | ||
| 400 | u64 block_end; | ||
| 401 | |||
| 402 | block = list_first_entry_or_null(&dfs, | ||
| 403 | struct drm_buddy_block, | ||
| 404 | tmp_link); | ||
| 405 | if (!block) | ||
| 406 | break; | ||
| 407 | |||
| 408 | list_del(&block->tmp_link); | ||
| 409 | |||
| 410 | block_start = drm_buddy_block_offset(block); | ||
| 411 | block_end = block_start + drm_buddy_block_size(mm, block) - 1; | ||
| 412 | |||
| 413 | if (!overlaps(start, end, block_start, block_end)) | ||
| 414 | continue; | ||
| 415 | |||
| 416 | if (drm_buddy_block_is_allocated(block)) { | ||
| 417 | err = -ENOSPC; | ||
| 418 | goto err_free; | ||
| 419 | } | ||
| 420 | |||
| 421 | if (contains(start, end, block_start, block_end)) { | ||
| 422 | if (!drm_buddy_block_is_free(block)) { | ||
| 423 | err = -ENOSPC; | ||
| 424 | goto err_free; | ||
| 425 | } | ||
| 426 | |||
| 427 | mark_allocated(block); | ||
| 428 | mm->avail -= drm_buddy_block_size(mm, block); | ||
| 429 | list_add_tail(&block->link, &allocated); | ||
| 430 | continue; | ||
| 431 | } | ||
| 432 | |||
| 433 | if (!drm_buddy_block_is_split(block)) { | ||
| 434 | err = split_block(mm, block); | ||
| 435 | if (unlikely(err)) | ||
| 436 | goto err_undo; | ||
| 437 | } | ||
| 438 | |||
| 439 | list_add(&block->right->tmp_link, &dfs); | ||
| 440 | list_add(&block->left->tmp_link, &dfs); | ||
| 441 | } while (1); | ||
| 442 | |||
| 443 | list_splice_tail(&allocated, blocks); | ||
| 444 | return 0; | ||
| 445 | |||
| 446 | err_undo: | ||
| 447 | /* | ||
| 448 | * We really don't want to leave around a bunch of split blocks, since | ||
| 449 | * bigger is better, so make sure we merge everything back before we | ||
| 450 | * free the allocated blocks. | ||
| 451 | */ | ||
| 452 | buddy = get_buddy(block); | ||
| 453 | if (buddy && | ||
| 454 | (drm_buddy_block_is_free(block) && | ||
| 455 | drm_buddy_block_is_free(buddy))) | ||
| 456 | __drm_buddy_free(mm, block); | ||
| 457 | |||
| 458 | err_free: | ||
| 459 | drm_buddy_free_list(mm, &allocated); | ||
| 460 | return err; | ||
| 461 | } | ||
| 462 | EXPORT_SYMBOL(drm_buddy_alloc_range); | ||
| 463 | |||
| 464 | /** | ||
| 465 | * drm_buddy_block_print - print block information | ||
| 466 | * | ||
| 467 | * @mm: DRM buddy manager | ||
| 468 | * @block: DRM buddy block | ||
| 469 | * @p: DRM printer to use | ||
| 470 | */ | ||
| 471 | void drm_buddy_block_print(struct drm_buddy *mm, | ||
| 472 | struct drm_buddy_block *block, | ||
| 473 | struct drm_printer *p) | ||
| 474 | { | ||
| 475 | u64 start = drm_buddy_block_offset(block); | ||
| 476 | u64 size = drm_buddy_block_size(mm, block); | ||
| 477 | |||
| 478 | drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); | ||
| 479 | } | ||
| 480 | EXPORT_SYMBOL(drm_buddy_block_print); | ||
| 481 | |||
| 482 | /** | ||
| 483 | * drm_buddy_print - print allocator state | ||
| 484 | * | ||
| 485 | * @mm: DRM buddy manager | ||
| 486 | * @p: DRM printer to use | ||
| 487 | */ | ||
| 488 | void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) | ||
| 489 | { | ||
| 490 | int order; | ||
| 491 | |||
| 492 | drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", | ||
| 493 | mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); | ||
| 494 | |||
| 495 | for (order = mm->max_order; order >= 0; order--) { | ||
| 496 | struct drm_buddy_block *block; | ||
| 497 | u64 count = 0, free; | ||
| 498 | |||
| 499 | list_for_each_entry(block, &mm->free_list[order], link) { | ||
| 500 | BUG_ON(!drm_buddy_block_is_free(block)); | ||
| 501 | count++; | ||
| 502 | } | ||
| 503 | |||
| 504 | drm_printf(p, "order-%d ", order); | ||
| 505 | |||
| 506 | free = count * (mm->chunk_size << order); | ||
| 507 | if (free < SZ_1M) | ||
| 508 | drm_printf(p, "free: %lluKiB", free >> 10); | ||
| 509 | else | ||
| 510 | drm_printf(p, "free: %lluMiB", free >> 20); | ||
| 511 | |||
| 512 | drm_printf(p, ", pages: %llu\n", count); | ||
| 513 | } | ||
| 514 | } | ||
| 515 | EXPORT_SYMBOL(drm_buddy_print); | ||
| 516 | |||
| 517 | static void drm_buddy_module_exit(void) | ||
| 518 | { | ||
| 519 | kmem_cache_destroy(slab_blocks); | ||
| 520 | } | ||
| 521 | |||
| 522 | static int __init drm_buddy_module_init(void) | ||
| 523 | { | ||
| 524 | slab_blocks = KMEM_CACHE(drm_buddy_block, 0); | ||
| 525 | if (!slab_blocks) | ||
| 526 | return -ENOMEM; | ||
| 527 | |||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | |||
| 531 | module_init(drm_buddy_module_init); | ||
| 532 | module_exit(drm_buddy_module_exit); | ||
| 533 | |||
| 534 | MODULE_DESCRIPTION("DRM Buddy Allocator"); | ||
| 535 | MODULE_LICENSE("Dual MIT/GPL"); | ||
| @@ -82,6 +82,10 @@ · 81 unmodified lines | |||
| 82 | * driver boot-up state too. Drivers can access this blob through | 82 | * driver boot-up state too. Drivers can access this blob through |
| 83 | * &drm_crtc_state.gamma_lut. | 83 | * &drm_crtc_state.gamma_lut. |
| 84 | * | 84 | * |
| 85 | * Note that for mostly historical reasons stemming from Xorg heritage, | ||
| 86 | * this is also used to store the color map (also sometimes color lut, CLUT | ||
| 87 | * or color palette) for indexed formats like DRM_FORMAT_C8. | ||
| 88 | * | ||
| 85 | * “GAMMA_LUT_SIZE”: | 89 | * “GAMMA_LUT_SIZE”: |
| 86 | * Unsigned range property to give the size of the lookup table to be set | 90 | * Unsigned range property to give the size of the lookup table to be set |
| 87 | * on the GAMMA_LUT property (the size depends on the underlying hardware). | 91 | * on the GAMMA_LUT property (the size depends on the underlying hardware). |
| @@ -28,36 +28,9 @@ · 27 unmodified lines | |||
| 28 | 28 | ||
| 29 | #include <drm/drm_connector.h> | 29 | #include <drm/drm_connector.h> |
| 30 | #include <drm/drm_crtc.h> | 30 | #include <drm/drm_crtc.h> |
| 31 | #include <drm/drm_dp_helper.h> | ||
| 32 | #include <drm/drm_encoder.h> | 31 | #include <drm/drm_encoder.h> |
| 33 | #include <drm/drm_modes.h> | 32 | #include <drm/drm_modes.h> |
| 34 | 33 | ||
| 35 | /* drm_dp_aux_dev.c */ | ||
| 36 | #ifdef CONFIG_DRM_DP_AUX_CHARDEV | ||
| 37 | int drm_dp_aux_dev_init(void); | ||
| 38 | void drm_dp_aux_dev_exit(void); | ||
| 39 | int drm_dp_aux_register_devnode(struct drm_dp_aux *aux); | ||
| 40 | void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux); | ||
| 41 | #else | ||
| 42 | static inline int drm_dp_aux_dev_init(void) | ||
| 43 | { | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 47 | static inline void drm_dp_aux_dev_exit(void) | ||
| 48 | { | ||
| 49 | } | ||
| 50 | |||
| 51 | static inline int drm_dp_aux_register_devnode(struct drm_dp_aux *aux) | ||
| 52 | { | ||
| 53 | return 0; | ||
| 54 | } | ||
| 55 | |||
| 56 | static inline void drm_dp_aux_unregister_devnode(struct drm_dp_aux *aux) | ||
| 57 | { | ||
| 58 | } | ||
| 59 | #endif | ||
| 60 | |||
| 61 | /* drm_probe_helper.c */ | 34 | /* drm_probe_helper.c */ |
| 62 | enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc, | 35 | enum drm_mode_status drm_crtc_mode_valid(struct drm_crtc *crtc, |
| 63 | const struct drm_display_mode *mode); | 36 | const struct drm_display_mode *mode); |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
| 13 | #include <linux/byteorder/generic.h> | 13 | #include <linux/byteorder/generic.h> |
| 14 | #include <drm/drm_print.h> | 14 | #include <drm/drm_print.h> |
| 15 | #include <drm/drm_dp_helper.h> | 15 | #include <drm/dp/drm_dp_helper.h> |
| 16 | #include <drm/drm_dsc.h> | 16 | #include <drm/drm_dsc.h> |
| 17 | 17 | ||
| 18 | /** | 18 | /** |
| @@ -93,6 +93,8 @@ static int oui(u8 first, u8 second, u8 third) · 92 unmodified lines | |||
| 93 | /* Non desktop display (i.e. HMD) */ | 93 | /* Non desktop display (i.e. HMD) */ |
| 94 | #define EDID_QUIRK_NON_DESKTOP (1 << 12) | 94 | #define EDID_QUIRK_NON_DESKTOP (1 << 12) |
| 95 | 95 | ||
| 96 | #define MICROSOFT_IEEE_OUI 0xca125c | ||
| 97 | |||
| 96 | struct detailed_mode_closure { | 98 | struct detailed_mode_closure { |
| 97 | struct drm_connector *connector; | 99 | struct drm_connector *connector; |
| 98 | struct edid *edid; | 100 | struct edid *edid; |
| @@ -212,9 +214,7 @@ static const struct edid_quirk { · 113 unmodified lines | |||
| 212 | 214 | ||
| 213 | /* Windows Mixed Reality Headsets */ | 215 | /* Windows Mixed Reality Headsets */ |
| 214 | EDID_QUIRK('A', 'C', 'R', 0x7fce, EDID_QUIRK_NON_DESKTOP), | 216 | EDID_QUIRK('A', 'C', 'R', 0x7fce, EDID_QUIRK_NON_DESKTOP), |
| 215 | EDID_QUIRK('H', 'P', 'N', 0x3515, EDID_QUIRK_NON_DESKTOP), | ||
| 216 | EDID_QUIRK('L', 'E', 'N', 0x0408, EDID_QUIRK_NON_DESKTOP), | 217 | EDID_QUIRK('L', 'E', 'N', 0x0408, EDID_QUIRK_NON_DESKTOP), |
| 217 | EDID_QUIRK('L', 'E', 'N', 0xb800, EDID_QUIRK_NON_DESKTOP), | ||
| 218 | EDID_QUIRK('F', 'U', 'J', 0x1970, EDID_QUIRK_NON_DESKTOP), | 218 | EDID_QUIRK('F', 'U', 'J', 0x1970, EDID_QUIRK_NON_DESKTOP), |
| 219 | EDID_QUIRK('D', 'E', 'L', 0x7fce, EDID_QUIRK_NON_DESKTOP), | 219 | EDID_QUIRK('D', 'E', 'L', 0x7fce, EDID_QUIRK_NON_DESKTOP), |
| 220 | EDID_QUIRK('S', 'E', 'C', 0x144a, EDID_QUIRK_NON_DESKTOP), | 220 | EDID_QUIRK('S', 'E', 'C', 0x144a, EDID_QUIRK_NON_DESKTOP), |
| @@ -3776,7 +3776,7 @@ static int do_y420vdb_modes(struct drm_connector *connector, · 3555 unmodified lines | |||
| 3776 | } | 3776 | } |
| 3777 | 3777 | ||
| 3778 | if (modes > 0) | 3778 | if (modes > 0) |
| 3779 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | 3779 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; |
| 3780 | return modes; | 3780 | return modes; |
| 3781 | } | 3781 | } |
| 3782 | 3782 | ||
| @@ -4222,6 +4222,17 @@ static bool cea_db_is_hdmi_forum_vsdb(const u8 *db) · 439 unmodified lines | |||
| 4222 | return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI; | 4222 | return oui(db[3], db[2], db[1]) == HDMI_FORUM_IEEE_OUI; |
| 4223 | } | 4223 | } |
| 4224 | 4224 | ||
| 4225 | static bool cea_db_is_microsoft_vsdb(const u8 *db) | ||
| 4226 | { | ||
| 4227 | if (cea_db_tag(db) != VENDOR_BLOCK) | ||
| 4228 | return false; | ||
| 4229 | |||
| 4230 | if (cea_db_payload_len(db) != 21) | ||
| 4231 | return false; | ||
| 4232 | |||
| 4233 | return oui(db[3], db[2], db[1]) == MICROSOFT_IEEE_OUI; | ||
| 4234 | } | ||
| 4235 | |||
| 4225 | static bool cea_db_is_vcdb(const u8 *db) | 4236 | static bool cea_db_is_vcdb(const u8 *db) |
| 4226 | { | 4237 | { |
| 4227 | if (cea_db_tag(db) != USE_EXTENDED_TAG) | 4238 | if (cea_db_tag(db) != USE_EXTENDED_TAG) |
| @@ -4279,7 +4290,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, · 51 unmodified lines | |||
| 4279 | if (map_len == 0) { | 4290 | if (map_len == 0) { |
| 4280 | /* All CEA modes support ycbcr420 sampling also.*/ | 4291 | /* All CEA modes support ycbcr420 sampling also.*/ |
| 4281 | hdmi->y420_cmdb_map = U64_MAX; | 4292 | hdmi->y420_cmdb_map = U64_MAX; |
| 4282 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | 4293 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; |
| 4283 | return; | 4294 | return; |
| 4284 | } | 4295 | } |
| 4285 | 4296 | ||
| @@ -4302,7 +4313,7 @@ static void drm_parse_y420cmdb_bitmap(struct drm_connector *connector, · 16 unmodified lines | |||
| 4302 | map |= (u64)db[2 + count] << (8 * count); | 4313 | map |= (u64)db[2 + count] << (8 * count); |
| 4303 | 4314 | ||
| 4304 | if (map) | 4315 | if (map) |
| 4305 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB420; | 4316 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR420; |
| 4306 | 4317 | ||
| 4307 | hdmi->y420_cmdb_map = map; | 4318 | hdmi->y420_cmdb_map = map; |
| 4308 | } | 4319 | } |
| @@ -5075,21 +5086,21 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, · 766 unmodified lines | |||
| 5075 | 5086 | ||
| 5076 | if (hdmi[6] & DRM_EDID_HDMI_DC_30) { | 5087 | if (hdmi[6] & DRM_EDID_HDMI_DC_30) { |
| 5077 | dc_bpc = 10; | 5088 | dc_bpc = 10; |
| 5078 | info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_30; | 5089 | info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_30; |
| 5079 | DRM_DEBUG("%s: HDMI sink does deep color 30.\n", | 5090 | DRM_DEBUG("%s: HDMI sink does deep color 30.\n", |
| 5080 | connector->name); | 5091 | connector->name); |
| 5081 | } | 5092 | } |
| 5082 | 5093 | ||
| 5083 | if (hdmi[6] & DRM_EDID_HDMI_DC_36) { | 5094 | if (hdmi[6] & DRM_EDID_HDMI_DC_36) { |
| 5084 | dc_bpc = 12; | 5095 | dc_bpc = 12; |
| 5085 | info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_36; | 5096 | info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_36; |
| 5086 | DRM_DEBUG("%s: HDMI sink does deep color 36.\n", | 5097 | DRM_DEBUG("%s: HDMI sink does deep color 36.\n", |
| 5087 | connector->name); | 5098 | connector->name); |
| 5088 | } | 5099 | } |
| 5089 | 5100 | ||
| 5090 | if (hdmi[6] & DRM_EDID_HDMI_DC_48) { | 5101 | if (hdmi[6] & DRM_EDID_HDMI_DC_48) { |
| 5091 | dc_bpc = 16; | 5102 | dc_bpc = 16; |
| 5092 | info->edid_hdmi_dc_modes |= DRM_EDID_HDMI_DC_48; | 5103 | info->edid_hdmi_rgb444_dc_modes |= DRM_EDID_HDMI_DC_48; |
| 5093 | DRM_DEBUG("%s: HDMI sink does deep color 48.\n", | 5104 | DRM_DEBUG("%s: HDMI sink does deep color 48.\n", |
| 5094 | connector->name); | 5105 | connector->name); |
| 5095 | } | 5106 | } |
| @@ -5104,16 +5115,9 @@ static void drm_parse_hdmi_deep_color_info(struct drm_connector *connector, · 8 unmodified lines | |||
| 5104 | connector->name, dc_bpc); | 5115 | connector->name, dc_bpc); |
| 5105 | info->bpc = dc_bpc; | 5116 | info->bpc = dc_bpc; |
| 5106 | 5117 | ||
| 5107 | /* | ||
| 5108 | * Deep color support mandates RGB444 support for all video | ||
| 5109 | * modes and forbids YCRCB422 support for all video modes per | ||
| 5110 | * HDMI 1.3 spec. | ||
| 5111 | */ | ||
| 5112 | info->color_formats = DRM_COLOR_FORMAT_RGB444; | ||
| 5113 | |||
| 5114 | /* YCRCB444 is optional according to spec. */ | 5118 | /* YCRCB444 is optional according to spec. */ |
| 5115 | if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { | 5119 | if (hdmi[6] & DRM_EDID_HDMI_DC_Y444) { |
| 5116 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | 5120 | info->edid_hdmi_ycbcr444_dc_modes = info->edid_hdmi_rgb444_dc_modes; |
| 5117 | DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", | 5121 | DRM_DEBUG("%s: HDMI sink does YCRCB444 in deep color.\n", |
| 5118 | connector->name); | 5122 | connector->name); |
| 5119 | } | 5123 | } |
| @@ -5149,6 +5153,25 @@ drm_parse_hdmi_vsdb_video(struct drm_connector *connector, const u8 *db) · 29 unmodified lines | |||
| 5149 | drm_parse_hdmi_deep_color_info(connector, db); | 5153 | drm_parse_hdmi_deep_color_info(connector, db); |
| 5150 | } | 5154 | } |
| 5151 | 5155 | ||
| 5156 | /* | ||
| 5157 | * See EDID extension for head-mounted and specialized monitors, specified at: | ||
| 5158 | * https://docs.microsoft.com/en-us/windows-hardware/drivers/display/specialized-monitors-edid-extension | ||
| 5159 | */ | ||
| 5160 | static void drm_parse_microsoft_vsdb(struct drm_connector *connector, | ||
| 5161 | const u8 *db) | ||
| 5162 | { | ||
| 5163 | struct drm_display_info *info = &connector->display_info; | ||
| 5164 | u8 version = db[4]; | ||
| 5165 | bool desktop_usage = db[5] & BIT(6); | ||
| 5166 | |||
| 5167 | /* Version 1 and 2 for HMDs, version 3 flags desktop usage explicitly */ | ||
| 5168 | if (version == 1 || version == 2 || (version == 3 && !desktop_usage)) | ||
| 5169 | info->non_desktop = true; | ||
| 5170 | |||
| 5171 | drm_dbg_kms(connector->dev, "HMD or specialized display VSDB version %u: 0x%02x\n", | ||
| 5172 | version, db[5]); | ||
| 5173 | } | ||
| 5174 | |||
| 5152 | static void drm_parse_cea_ext(struct drm_connector *connector, | 5175 | static void drm_parse_cea_ext(struct drm_connector *connector, |
| 5153 | const struct edid *edid) | 5176 | const struct edid *edid) |
| 5154 | { | 5177 | { |
| @@ -5165,9 +5188,9 @@ static void drm_parse_cea_ext(struct drm_connector *connector, · 10 unmodified lines | |||
| 5165 | /* The existence of a CEA block should imply RGB support */ | 5188 | /* The existence of a CEA block should imply RGB support */ |
| 5166 | info->color_formats = DRM_COLOR_FORMAT_RGB444; | 5189 | info->color_formats = DRM_COLOR_FORMAT_RGB444; |
| 5167 | if (edid_ext[3] & EDID_CEA_YCRCB444) | 5190 | if (edid_ext[3] & EDID_CEA_YCRCB444) |
| 5168 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | 5191 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; |
| 5169 | if (edid_ext[3] & EDID_CEA_YCRCB422) | 5192 | if (edid_ext[3] & EDID_CEA_YCRCB422) |
| 5170 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | 5193 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; |
| 5171 | 5194 | ||
| 5172 | if (cea_db_offsets(edid_ext, &start, &end)) | 5195 | if (cea_db_offsets(edid_ext, &start, &end)) |
| 5173 | return; | 5196 | return; |
| @@ -5179,6 +5202,8 @@ static void drm_parse_cea_ext(struct drm_connector *connector, · 5 unmodified lines | |||
| 5179 | drm_parse_hdmi_vsdb_video(connector, db); | 5202 | drm_parse_hdmi_vsdb_video(connector, db); |
| 5180 | if (cea_db_is_hdmi_forum_vsdb(db)) | 5203 | if (cea_db_is_hdmi_forum_vsdb(db)) |
| 5181 | drm_parse_hdmi_forum_vsdb(connector, db); | 5204 | drm_parse_hdmi_forum_vsdb(connector, db); |
| 5205 | if (cea_db_is_microsoft_vsdb(db)) | ||
| 5206 | drm_parse_microsoft_vsdb(connector, db); | ||
| 5182 | if (cea_db_is_y420cmdb(db)) | 5207 | if (cea_db_is_y420cmdb(db)) |
| 5183 | drm_parse_y420cmdb_bitmap(connector, db); | 5208 | drm_parse_y420cmdb_bitmap(connector, db); |
| 5184 | if (cea_db_is_vcdb(db)) | 5209 | if (cea_db_is_vcdb(db)) |
| @@ -5333,17 +5358,13 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi · 148 unmodified lines | |||
| 5333 | info->width_mm = edid->width_cm * 10; | 5358 | info->width_mm = edid->width_cm * 10; |
| 5334 | info->height_mm = edid->height_cm * 10; | 5359 | info->height_mm = edid->height_cm * 10; |
| 5335 | 5360 | ||
| 5336 | info->non_desktop = !!(quirks & EDID_QUIRK_NON_DESKTOP); | ||
| 5337 | |||
| 5338 | drm_get_monitor_range(connector, edid); | 5361 | drm_get_monitor_range(connector, edid); |
| 5339 | 5362 | ||
| 5340 | DRM_DEBUG_KMS("non_desktop set to %d\n", info->non_desktop); | ||
| 5341 | |||
| 5342 | if (edid->revision < 3) | 5363 | if (edid->revision < 3) |
| 5343 | return quirks; | 5364 | goto out; |
| 5344 | 5365 | ||
| 5345 | if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) | 5366 | if (!(edid->input & DRM_EDID_INPUT_DIGITAL)) |
| 5346 | return quirks; | 5367 | goto out; |
| 5347 | 5368 | ||
| 5348 | drm_parse_cea_ext(connector, edid); | 5369 | drm_parse_cea_ext(connector, edid); |
| 5349 | 5370 | ||
| @@ -5363,7 +5384,7 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi · 13 unmodified lines | |||
| 5363 | 5384 | ||
| 5364 | /* Only defined for 1.4 with digital displays */ | 5385 | /* Only defined for 1.4 with digital displays */ |
| 5365 | if (edid->revision < 4) | 5386 | if (edid->revision < 4) |
| 5366 | return quirks; | 5387 | goto out; |
| 5367 | 5388 | ||
| 5368 | switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { | 5389 | switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) { |
| 5369 | case DRM_EDID_DIGITAL_DEPTH_6: | 5390 | case DRM_EDID_DIGITAL_DEPTH_6: |
| @@ -5395,17 +5416,25 @@ u32 drm_add_display_info(struct drm_connector *connector, const struct edid *edi · 25 unmodified lines | |||
| 5395 | 5416 | ||
| 5396 | info->color_formats |= DRM_COLOR_FORMAT_RGB444; | 5417 | info->color_formats |= DRM_COLOR_FORMAT_RGB444; |
| 5397 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) | 5418 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB444) |
| 5398 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB444; | 5419 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR444; |
| 5399 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) | 5420 | if (edid->features & DRM_EDID_FEATURE_RGB_YCRCB422) |
| 5400 | info->color_formats |= DRM_COLOR_FORMAT_YCRCB422; | 5421 | info->color_formats |= DRM_COLOR_FORMAT_YCBCR422; |
| 5401 | 5422 | ||
| 5402 | drm_update_mso(connector, edid); | 5423 | drm_update_mso(connector, edid); |
| 5403 | 5424 | ||
| 5425 | out: | ||
| 5426 | if (quirks & EDID_QUIRK_NON_DESKTOP) { | ||
| 5427 | drm_dbg_kms(connector->dev, "Non-desktop display%s\n", | ||
| 5428 | info->non_desktop ? " (redundant quirk)" : ""); | ||
| 5429 | info->non_desktop = true; | ||
| 5430 | } | ||
| 5431 | |||
| 5404 | return quirks; | 5432 | return quirks; |
| 5405 | } | 5433 | } |
| 5406 | 5434 | ||
| 5407 | static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, | 5435 | static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *dev, |
| 5408 | struct displayid_detailed_timings_1 *timings) | 5436 | struct displayid_detailed_timings_1 *timings, |
| 5437 | bool type_7) | ||
| 5409 | { | 5438 | { |
| 5410 | struct drm_display_mode *mode; | 5439 | struct drm_display_mode *mode; |
| 5411 | unsigned pixel_clock = (timings->pixel_clock[0] | | 5440 | unsigned pixel_clock = (timings->pixel_clock[0] | |
| @@ -5426,7 +5455,8 @@ static struct drm_display_mode *drm_mode_displayid_detailed(struct drm_device *d · 14 unmodified lines | |||
| 5426 | if (!mode) | 5455 | if (!mode) |
| 5427 | return NULL; | 5456 | return NULL; |
| 5428 | 5457 | ||
| 5429 | mode->clock = pixel_clock * 10; | 5458 | /* resolution is kHz for type VII, and 10 kHz for type I */ |
| 5459 | mode->clock = type_7 ? pixel_clock : pixel_clock * 10; | ||
| 5430 | mode->hdisplay = hactive; | 5460 | mode->hdisplay = hactive; |
| 5431 | mode->hsync_start = mode->hdisplay + hsync; | 5461 | mode->hsync_start = mode->hdisplay + hsync; |
| 5432 | mode->hsync_end = mode->hsync_start + hsync_width; | 5462 | mode->hsync_end = mode->hsync_start + hsync_width; |
| @@ -5457,6 +5487,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, · 24 unmodified lines | |||
| 5457 | int num_timings; | 5487 | int num_timings; |
| 5458 | struct drm_display_mode *newmode; | 5488 | struct drm_display_mode *newmode; |
| 5459 | int num_modes = 0; | 5489 | int num_modes = 0; |
| 5490 | bool type_7 = block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING; | ||
| 5460 | /* blocks must be multiple of 20 bytes length */ | 5491 | /* blocks must be multiple of 20 bytes length */ |
| 5461 | if (block->num_bytes % 20) | 5492 | if (block->num_bytes % 20) |
| 5462 | return 0; | 5493 | return 0; |
| @@ -5465,7 +5496,7 @@ static int add_displayid_detailed_1_modes(struct drm_connector *connector, · 2 unmodified lines | |||
| 5465 | for (i = 0; i < num_timings; i++) { | 5496 | for (i = 0; i < num_timings; i++) { |
| 5466 | struct displayid_detailed_timings_1 *timings = &det->timings[i]; | 5497 | struct displayid_detailed_timings_1 *timings = &det->timings[i]; |
| 5467 | 5498 | ||
| 5468 | newmode = drm_mode_displayid_detailed(connector->dev, timings); | 5499 | newmode = drm_mode_displayid_detailed(connector->dev, timings, type_7); |
| 5469 | if (!newmode) | 5500 | if (!newmode) |
| 5470 | continue; | 5501 | continue; |
| 5471 | 5502 | ||
| @@ -5484,7 +5515,8 @@ static int add_displayid_detailed_modes(struct drm_connector *connector, · 12 unmodified lines | |||
| 5484 | 5515 | ||
| 5485 | displayid_iter_edid_begin(edid, &iter); | 5516 | displayid_iter_edid_begin(edid, &iter); |
| 5486 | displayid_iter_for_each(block, &iter) { | 5517 | displayid_iter_for_each(block, &iter) { |
| 5487 | if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING) | 5518 | if (block->tag == DATA_BLOCK_TYPE_1_DETAILED_TIMING || |
| 5519 | block->tag == DATA_BLOCK_2_TYPE_7_DETAILED_TIMING) | ||
| 5488 | num_modes += add_displayid_detailed_1_modes(connector, block); | 5520 | num_modes += add_displayid_detailed_1_modes(connector, block); |
| 5489 | } | 5521 | } |
| 5490 | displayid_iter_end(&iter); | 5522 | displayid_iter_end(&iter); |
| @@ -5652,7 +5684,7 @@ static bool is_hdmi2_sink(const struct drm_connector *connector) · 161 unmodified lines | |||
| 5652 | return true; | 5684 | return true; |
| 5653 | 5685 | ||
| 5654 | return connector->display_info.hdmi.scdc.supported || | 5686 | return connector->display_info.hdmi.scdc.supported || |
| 5655 | connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB420; | 5687 | connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR420; |
| 5656 | } | 5688 | } |
| 5657 | 5689 | ||
| 5658 | static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) | 5690 | static inline bool is_eotf_supported(u8 output_eotf, u8 sink_eotf) |
| @@ -5891,13 +5923,13 @@ static const u32 hdmi_colorimetry_val[] = { · 232 unmodified lines | |||
| 5891 | #undef ACE | 5923 | #undef ACE |
| 5892 | 5924 | ||
| 5893 | /** | 5925 | /** |
| 5894 | * drm_hdmi_avi_infoframe_colorspace() - fill the HDMI AVI infoframe | 5926 | * drm_hdmi_avi_infoframe_colorimetry() - fill the HDMI AVI infoframe |
| 5895 | * colorspace information | 5927 | * colorimetry information |
| 5896 | * @frame: HDMI AVI infoframe | 5928 | * @frame: HDMI AVI infoframe |
| 5897 | * @conn_state: connector state | 5929 | * @conn_state: connector state |
| 5898 | */ | 5930 | */ |
| 5899 | void | 5931 | void |
| 5900 | drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, | 5932 | drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, |
| 5901 | const struct drm_connector_state *conn_state) | 5933 | const struct drm_connector_state *conn_state) |
| 5902 | { | 5934 | { |
| 5903 | u32 colorimetry_val; | 5935 | u32 colorimetry_val; |
| @@ -5916,7 +5948,7 @@ drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, · 12 unmodified lines | |||
| 5916 | frame->extended_colorimetry = (colorimetry_val >> 2) & | 5948 | frame->extended_colorimetry = (colorimetry_val >> 2) & |
| 5917 | EXTENDED_COLORIMETRY_MASK; | 5949 | EXTENDED_COLORIMETRY_MASK; |
| 5918 | } | 5950 | } |
| 5919 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorspace); | 5951 | EXPORT_SYMBOL(drm_hdmi_avi_infoframe_colorimetry); |
| 5920 | 5952 | ||
| 5921 | /** | 5953 | /** |
| 5922 | * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe | 5954 | * drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe |
| @@ -61,17 +61,3 @@ MODULE_PARM_DESC(edid_firmware, · 60 unmodified lines | |||
| 61 | "DEPRECATED. Use drm.edid_firmware module parameter instead."); | 61 | "DEPRECATED. Use drm.edid_firmware module parameter instead."); |
| 62 | 62 | ||
| 63 | #endif | 63 | #endif |
| 64 | |||
| 65 | static int __init drm_kms_helper_init(void) | ||
| 66 | { | ||
| 67 | return drm_dp_aux_dev_init(); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void __exit drm_kms_helper_exit(void) | ||
| 71 | { | ||
| 72 | /* Call exit functions from specific kms helpers here */ | ||
| 73 | drm_dp_aux_dev_exit(); | ||
| 74 | } | ||
| 75 | |||
| 76 | module_init(drm_kms_helper_init); | ||
| 77 | module_exit(drm_kms_helper_exit); | ||
| @@ -202,17 +202,13 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane · 201 unmodified lines | |||
| 202 | 202 | ||
| 203 | memcpy(formats_ptr(blob_data), plane->format_types, formats_size); | 203 | memcpy(formats_ptr(blob_data), plane->format_types, formats_size); |
| 204 | 204 | ||
| 205 | /* If we can't determine support, just bail */ | ||
| 206 | if (!plane->funcs->format_mod_supported) | ||
| 207 | goto done; | ||
| 208 | |||
| 209 | mod = modifiers_ptr(blob_data); | 205 | mod = modifiers_ptr(blob_data); |
| 210 | for (i = 0; i < plane->modifier_count; i++) { | 206 | for (i = 0; i < plane->modifier_count; i++) { |
| 211 | for (j = 0; j < plane->format_count; j++) { | 207 | for (j = 0; j < plane->format_count; j++) { |
| 212 | if (plane->funcs->format_mod_supported(plane, | 208 | if (!plane->funcs->format_mod_supported || |
| 209 | plane->funcs->format_mod_supported(plane, | ||
| 213 | plane->format_types[j], | 210 | plane->format_types[j], |
| 214 | plane->modifiers[i])) { | 211 | plane->modifiers[i])) { |
| 215 | |||
| 216 | mod->formats |= 1ULL << j; | 212 | mod->formats |= 1ULL << j; |
| 217 | } | 213 | } |
| 218 | } | 214 | } |
| @@ -223,7 +219,6 @@ static int create_in_format_blob(struct drm_device *dev, struct drm_plane *plane · 4 unmodified lines | |||
| 223 | mod++; | 219 | mod++; |
| 224 | } | 220 | } |
| 225 | 221 | ||
| 226 | done: | ||
| 227 | drm_object_attach_property(&plane->base, config->modifiers_property, | 222 | drm_object_attach_property(&plane->base, config->modifiers_property, |
| 228 | blob->base.id); | 223 | blob->base.id); |
| 229 | 224 | ||
| @@ -387,7 +387,8 @@ static void drm_privacy_screen_device_release(struct device *dev) · 386 unmodified lines | |||
| 387 | * * An ERR_PTR(errno) on failure. | 387 | * * An ERR_PTR(errno) on failure. |
| 388 | */ | 388 | */ |
| 389 | struct drm_privacy_screen *drm_privacy_screen_register( | 389 | struct drm_privacy_screen *drm_privacy_screen_register( |
| 390 | struct device *parent, const struct drm_privacy_screen_ops *ops) | 390 | struct device *parent, const struct drm_privacy_screen_ops *ops, |
| 391 | void *data) | ||
| 391 | { | 392 | { |
| 392 | struct drm_privacy_screen *priv; | 393 | struct drm_privacy_screen *priv; |
| 393 | int ret; | 394 | int ret; |
| @@ -404,6 +405,7 @@ struct drm_privacy_screen *drm_privacy_screen_register( · 10 unmodified lines | |||
| 404 | priv->dev.parent = parent; | 405 | priv->dev.parent = parent; |
| 405 | priv->dev.release = drm_privacy_screen_device_release; | 406 | priv->dev.release = drm_privacy_screen_device_release; |
| 406 | dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent)); | 407 | dev_set_name(&priv->dev, "privacy_screen-%s", dev_name(parent)); |
| 408 | priv->drvdata = data; | ||
| 407 | priv->ops = ops; | 409 | priv->ops = ops; |
| 408 | 410 | ||
| 409 | priv->ops->get_hw_state(priv); | 411 | priv->ops->get_hw_state(priv); |
| @@ -439,6 +441,7 @@ void drm_privacy_screen_unregister(struct drm_privacy_screen *priv) · 29 unmodified lines | |||
| 439 | mutex_unlock(&drm_privacy_screen_devs_lock); | 441 | mutex_unlock(&drm_privacy_screen_devs_lock); |
| 440 | 442 | ||
| 441 | mutex_lock(&priv->lock); | 443 | mutex_lock(&priv->lock); |
| 444 | priv->drvdata = NULL; | ||
| 442 | priv->ops = NULL; | 445 | priv->ops = NULL; |
| 443 | mutex_unlock(&priv->lock); | 446 | mutex_unlock(&priv->lock); |
| 444 | 447 | ||
| @@ -50,6 +50,13 @@ static bool __init detect_thinkpad_privacy_screen(void) · 49 unmodified lines | |||
| 50 | } | 50 | } |
| 51 | #endif | 51 | #endif |
| 52 | 52 | ||
| 53 | #if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN) | ||
| 54 | static bool __init detect_chromeos_privacy_screen(void) | ||
| 55 | { | ||
| 56 | return acpi_dev_present("GOOG0010", NULL, -1); | ||
| 57 | } | ||
| 58 | #endif | ||
| 59 | |||
| 53 | static const struct arch_init_data arch_init_data[] __initconst = { | 60 | static const struct arch_init_data arch_init_data[] __initconst = { |
| 54 | #if IS_ENABLED(CONFIG_THINKPAD_ACPI) | 61 | #if IS_ENABLED(CONFIG_THINKPAD_ACPI) |
| 55 | { | 62 | { |
| @@ -61,6 +68,16 @@ static const struct arch_init_data arch_init_data[] __initconst = { · 5 unmodified lines | |||
| 61 | .detect = detect_thinkpad_privacy_screen, | 68 | .detect = detect_thinkpad_privacy_screen, |
| 62 | }, | 69 | }, |
| 63 | #endif | 70 | #endif |
| 71 | #if IS_ENABLED(CONFIG_CHROMEOS_PRIVACY_SCREEN) | ||
| 72 | { | ||
| 73 | .lookup = { | ||
| 74 | .dev_id = NULL, | ||
| 75 | .con_id = NULL, | ||
| 76 | .provider = "privacy_screen-GOOG0010:00", | ||
| 77 | }, | ||
| 78 | .detect = detect_chromeos_privacy_screen, | ||
| 79 | }, | ||
| 80 | #endif | ||
| 64 | }; | 81 | }; |
| 65 | 82 | ||
| 66 | void __init drm_privacy_screen_lookup_init(void) | 83 | void __init drm_privacy_screen_lookup_init(void) |
| @@ -189,8 +189,7 @@ static int submit_fence_sync(struct etnaviv_gem_submit *submit) · 188 unmodified lines | |||
| 189 | continue; | 189 | continue; |
| 190 | 190 | ||
| 191 | if (bo->flags & ETNA_SUBMIT_BO_WRITE) { | 191 | if (bo->flags & ETNA_SUBMIT_BO_WRITE) { |
| 192 | ret = dma_resv_get_fences(robj, NULL, | 192 | ret = dma_resv_get_fences(robj, true, &bo->nr_shared, |
| 193 | &bo->nr_shared, | ||
| 194 | &bo->shared); | 193 | &bo->shared); |
| 195 | if (ret) | 194 | if (ret) |
| 196 | return ret; | 195 | return ret; |
| @@ -66,6 +66,7 @@ config DRM_EXYNOS_DP · 65 unmodified lines | |||
| 66 | bool "Exynos specific extensions for Analogix DP driver" | 66 | bool "Exynos specific extensions for Analogix DP driver" |
| 67 | depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON | 67 | depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON |
| 68 | select DRM_ANALOGIX_DP | 68 | select DRM_ANALOGIX_DP |
| 69 | select DRM_DP_HELPER | ||
| 69 | default DRM_EXYNOS | 70 | default DRM_EXYNOS |
| 70 | select DRM_PANEL | 71 | select DRM_PANEL |
| 71 | help | 72 | help |
| @@ -258,6 +258,7 @@ struct exynos_dsi { · 257 unmodified lines | |||
| 258 | struct list_head bridge_chain; | 258 | struct list_head bridge_chain; |
| 259 | struct drm_bridge *out_bridge; | 259 | struct drm_bridge *out_bridge; |
| 260 | struct device *dev; | 260 | struct device *dev; |
| 261 | struct drm_display_mode mode; | ||
| 261 | 262 | ||
| 262 | void __iomem *reg_base; | 263 | void __iomem *reg_base; |
| 263 | struct phy *phy; | 264 | struct phy *phy; |
| @@ -881,7 +882,7 @@ static int exynos_dsi_init_link(struct exynos_dsi *dsi) · 617 unmodified lines | |||
| 881 | 882 | ||
| 882 | static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) | 883 | static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi) |
| 883 | { | 884 | { |
| 884 | struct drm_display_mode *m = &dsi->encoder.crtc->state->adjusted_mode; | 885 | struct drm_display_mode *m = &dsi->mode; |
| 885 | unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; | 886 | unsigned int num_bits_resol = dsi->driver_data->num_bits_resol; |
| 886 | u32 reg; | 887 | u32 reg; |
| 887 | 888 | ||
| @@ -1446,6 +1447,15 @@ static void exynos_dsi_disable(struct drm_encoder *encoder) · 558 unmodified lines | |||
| 1446 | pm_runtime_put_sync(dsi->dev); | 1447 | pm_runtime_put_sync(dsi->dev); |
| 1447 | } | 1448 | } |
| 1448 | 1449 | ||
| 1450 | static void exynos_dsi_mode_set(struct drm_encoder *encoder, | ||
| 1451 | struct drm_display_mode *mode, | ||
| 1452 | struct drm_display_mode *adjusted_mode) | ||
| 1453 | { | ||
| 1454 | struct exynos_dsi *dsi = encoder_to_dsi(encoder); | ||
| 1455 | |||
| 1456 | drm_mode_copy(&dsi->mode, adjusted_mode); | ||
| 1457 | } | ||
| 1458 | |||
| 1449 | static enum drm_connector_status | 1459 | static enum drm_connector_status |
| 1450 | exynos_dsi_detect(struct drm_connector *connector, bool force) | 1460 | exynos_dsi_detect(struct drm_connector *connector, bool force) |
| 1451 | { | 1461 | { |
| @@ -1513,6 +1523,7 @@ static int exynos_dsi_create_connector(struct drm_encoder *encoder) · 61 unmodified lines | |||
| 1513 | static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { | 1523 | static const struct drm_encoder_helper_funcs exynos_dsi_encoder_helper_funcs = { |
| 1514 | .enable = exynos_dsi_enable, | 1524 | .enable = exynos_dsi_enable, |
| 1515 | .disable = exynos_dsi_disable, | 1525 | .disable = exynos_dsi_disable, |
| 1526 | .mode_set = exynos_dsi_mode_set, | ||
| 1516 | }; | 1527 | }; |
| 1517 | 1528 | ||
| 1518 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); | 1529 | MODULE_DEVICE_TABLE(of, exynos_dsi_of_match); |
| @@ -31,7 +31,7 @@ · 30 unmodified lines | |||
| 31 | 31 | ||
| 32 | #include <drm/drm_crtc.h> | 32 | #include <drm/drm_crtc.h> |
| 33 | #include <drm/drm_crtc_helper.h> | 33 | #include <drm/drm_crtc_helper.h> |
| 34 | #include <drm/drm_dp_helper.h> | 34 | #include <drm/dp/drm_dp_helper.h> |
| 35 | #include <drm/drm_simple_kms_helper.h> | 35 | #include <drm/drm_simple_kms_helper.h> |
| 36 | 36 | ||
| 37 | #include "gma_display.h" | 37 | #include "gma_display.h" |
| @@ -82,7 +82,6 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) · 44 unmodified lines | |||
| 82 | { | 82 | { |
| 83 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | 83 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
| 84 | int mode = MODE_I2C_START; | 84 | int mode = MODE_I2C_START; |
| 85 | int ret; | ||
| 86 | 85 | ||
| 87 | if (reading) | 86 | if (reading) |
| 88 | mode |= MODE_I2C_READ; | 87 | mode |= MODE_I2C_READ; |
| @@ -90,8 +89,7 @@ i2c_algo_dp_aux_address(struct i2c_adapter *adapter, u16 address, bool reading) · 1 unmodified line | |||
| 90 | mode |= MODE_I2C_WRITE; | 89 | mode |= MODE_I2C_WRITE; |
| 91 | algo_data->address = address; | 90 | algo_data->address = address; |
| 92 | algo_data->running = true; | 91 | algo_data->running = true; |
| 93 | ret = i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); | 92 | return i2c_algo_dp_aux_transaction(adapter, mode, 0, NULL); |
| 94 | return ret; | ||
| 95 | } | 93 | } |
| 96 | 94 | ||
| 97 | /* | 95 | /* |
| @@ -122,13 +120,11 @@ static int · 24 unmodified lines | |||
| 122 | i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) | 120 | i2c_algo_dp_aux_put_byte(struct i2c_adapter *adapter, u8 byte) |
| 123 | { | 121 | { |
| 124 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | 122 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
| 125 | int ret; | ||
| 126 | 123 | ||
| 127 | if (!algo_data->running) | 124 | if (!algo_data->running) |
| 128 | return -EIO; | 125 | return -EIO; |
| 129 | 126 | ||
| 130 | ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); | 127 | return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_WRITE, byte, NULL); |
| 131 | return ret; | ||
| 132 | } | 128 | } |
| 133 | 129 | ||
| 134 | /* | 130 | /* |
| @@ -139,13 +135,11 @@ static int · 4 unmodified lines | |||
| 139 | i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) | 135 | i2c_algo_dp_aux_get_byte(struct i2c_adapter *adapter, u8 *byte_ret) |
| 140 | { | 136 | { |
| 141 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; | 137 | struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data; |
| 142 | int ret; | ||
| 143 | 138 | ||
| 144 | if (!algo_data->running) | 139 | if (!algo_data->running) |
| 145 | return -EIO; | 140 | return -EIO; |
| 146 | 141 | ||
| 147 | ret = i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); | 142 | return i2c_algo_dp_aux_transaction(adapter, MODE_I2C_READ, 0, byte_ret); |
| 148 | return ret; | ||
| 149 | } | 143 | } |
| 150 | 144 | ||
| 151 | static int | 145 | static int |
| @@ -335,7 +335,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, · 334 unmodified lines | |||
| 335 | struct psb_gem_object *pobj; | 335 | struct psb_gem_object *pobj; |
| 336 | struct psb_gem_object *cursor_pobj = gma_crtc->cursor_pobj; | 336 | struct psb_gem_object *cursor_pobj = gma_crtc->cursor_pobj; |
| 337 | struct drm_gem_object *obj; | 337 | struct drm_gem_object *obj; |
| 338 | void *tmp_dst, *tmp_src; | 338 | void *tmp_dst; |
| 339 | int ret = 0, i, cursor_pages; | 339 | int ret = 0, i, cursor_pages; |
| 340 | 340 | ||
| 341 | /* If we didn't get a handle then turn the cursor off */ | 341 | /* If we didn't get a handle then turn the cursor off */ |
| @@ -400,9 +400,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc, · 58 unmodified lines | |||
| 400 | /* Copy the cursor to cursor mem */ | 400 | /* Copy the cursor to cursor mem */ |
| 401 | tmp_dst = dev_priv->vram_addr + cursor_pobj->offset; | 401 | tmp_dst = dev_priv->vram_addr + cursor_pobj->offset; |
| 402 | for (i = 0; i < cursor_pages; i++) { | 402 | for (i = 0; i < cursor_pages; i++) { |
| 403 | tmp_src = kmap(pobj->pages[i]); | 403 | memcpy_from_page(tmp_dst, pobj->pages[i], 0, PAGE_SIZE); |
| 404 | memcpy(tmp_dst, tmp_src, PAGE_SIZE); | ||
| 405 | kunmap(pobj->pages[i]); | ||
| 406 | tmp_dst += PAGE_SIZE; | 404 | tmp_dst += PAGE_SIZE; |
| 407 | } | 405 | } |
| 408 | 406 | ||
| @@ -6,7 +6,7 @@ · 5 unmodified lines | |||
| 6 | * Eric Anholt <eric@anholt.net> | 6 | * Eric Anholt <eric@anholt.net> |
| 7 | */ | 7 | */ |
| 8 | #include <drm/drm.h> | 8 | #include <drm/drm.h> |
| 9 | #include <drm/drm_dp_helper.h> | 9 | #include <drm/dp/drm_dp_helper.h> |
| 10 | 10 | ||
| 11 | #include "intel_bios.h" | 11 | #include "intel_bios.h" |
| 12 | #include "psb_drv.h" | 12 | #include "psb_drv.h" |
| @@ -184,17 +184,17 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver, · 183 unmodified lines | |||
| 184 | pd->invalid_pte = 0; | 184 | pd->invalid_pte = 0; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | v = kmap(pd->dummy_pt); | 187 | v = kmap_local_page(pd->dummy_pt); |
| 188 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) | 188 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) |
| 189 | v[i] = pd->invalid_pte; | 189 | v[i] = pd->invalid_pte; |
| 190 | 190 | ||
| 191 | kunmap(pd->dummy_pt); | 191 | kunmap_local(v); |
| 192 | 192 | ||
| 193 | v = kmap(pd->p); | 193 | v = kmap_local_page(pd->p); |
| 194 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) | 194 | for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i) |
| 195 | v[i] = pd->invalid_pde; | 195 | v[i] = pd->invalid_pde; |
| 196 | 196 | ||
| 197 | kunmap(pd->p); | 197 | kunmap_local(v); |
| 198 | 198 | ||
| 199 | clear_page(kmap(pd->dummy_page)); | 199 | clear_page(kmap(pd->dummy_page)); |
| 200 | kunmap(pd->dummy_page); | 200 | kunmap(pd->dummy_page); |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <drm/drm_gem_framebuffer_helper.h> | 20 | #include <drm/drm_gem_framebuffer_helper.h> |
| 21 | #include <drm/drm_gem_vram_helper.h> | 21 | #include <drm/drm_gem_vram_helper.h> |
| 22 | #include <drm/drm_managed.h> | 22 | #include <drm/drm_managed.h> |
| 23 | #include <drm/drm_module.h> | ||
| 23 | #include <drm/drm_vblank.h> | 24 | #include <drm/drm_vblank.h> |
| 24 | 25 | ||
| 25 | #include "hibmc_drm_drv.h" | 26 | #include "hibmc_drm_drv.h" |
| @@ -379,7 +380,7 @@ static struct pci_driver hibmc_pci_driver = { · 353 unmodified lines | |||
| 379 | .driver.pm = &hibmc_pm_ops, | 380 | .driver.pm = &hibmc_pm_ops, |
| 380 | }; | 381 | }; |
| 381 | 382 | ||
| 382 | module_pci_driver(hibmc_pci_driver); | 383 | drm_module_pci_driver(hibmc_pci_driver); |
| 383 | 384 | ||
| 384 | MODULE_DEVICE_TABLE(pci, hibmc_pci_table); | 385 | MODULE_DEVICE_TABLE(pci, hibmc_pci_table); |
| 385 | MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>"); | 386 | MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>"); |
| @@ -9,6 +9,7 @@ config DRM_I915 · 8 unmodified lines | |||
| 9 | # the shmem_readpage() which depends upon tmpfs | 9 | # the shmem_readpage() which depends upon tmpfs |
| 10 | select SHMEM | 10 | select SHMEM |
| 11 | select TMPFS | 11 | select TMPFS |
| 12 | select DRM_DP_HELPER | ||
| 12 | select DRM_KMS_HELPER | 13 | select DRM_KMS_HELPER |
| 13 | select DRM_PANEL | 14 | select DRM_PANEL |
| 14 | select DRM_MIPI_DSI | 15 | select DRM_MIPI_DSI |
| @@ -27,6 +28,7 @@ config DRM_I915 · 12 unmodified lines | |||
| 27 | select CEC_CORE if CEC_NOTIFIER | 28 | select CEC_CORE if CEC_NOTIFIER |
| 28 | select VMAP_PFN | 29 | select VMAP_PFN |
| 29 | select DRM_TTM | 30 | select DRM_TTM |
| 31 | select DRM_BUDDY | ||
| 30 | help | 32 | help |
| 31 | Choose this option if you have a system that has "Intel Graphics | 33 | Choose this option if you have a system that has "Intel Graphics |
| 32 | Media Accelerator" or "HD Graphics" integrated graphics, | 34 | Media Accelerator" or "HD Graphics" integrated graphics, |
| @@ -161,7 +161,6 @@ gem-y += \ · 160 unmodified lines | |||
| 161 | i915-y += \ | 161 | i915-y += \ |
| 162 | $(gem-y) \ | 162 | $(gem-y) \ |
| 163 | i915_active.o \ | 163 | i915_active.o \ |
| 164 | i915_buddy.o \ | ||
| 165 | i915_cmd_parser.o \ | 164 | i915_cmd_parser.o \ |
| 166 | i915_deps.o \ | 165 | i915_deps.o \ |
| 167 | i915_gem_evict.o \ | 166 | i915_gem_evict.o \ |
| @@ -25,7 +25,7 @@ · 24 unmodified lines | |||
| 25 | * | 25 | * |
| 26 | */ | 26 | */ |
| 27 | 27 | ||
| 28 | #include <drm/drm_dp_helper.h> | 28 | #include <drm/dp/drm_dp_helper.h> |
| 29 | 29 | ||
| 30 | #include "display/intel_display.h" | 30 | #include "display/intel_display.h" |
| 31 | #include "display/intel_display_types.h" | 31 | #include "display/intel_display_types.h" |
| @@ -38,7 +38,7 @@ · 37 unmodified lines | |||
| 38 | #include <drm/drm_atomic_helper.h> | 38 | #include <drm/drm_atomic_helper.h> |
| 39 | #include <drm/drm_atomic_uapi.h> | 39 | #include <drm/drm_atomic_uapi.h> |
| 40 | #include <drm/drm_damage_helper.h> | 40 | #include <drm/drm_damage_helper.h> |
| 41 | #include <drm/drm_dp_helper.h> | 41 | #include <drm/dp/drm_dp_helper.h> |
| 42 | #include <drm/drm_edid.h> | 42 | #include <drm/drm_edid.h> |
| 43 | #include <drm/drm_fourcc.h> | 43 | #include <drm/drm_fourcc.h> |
| 44 | #include <drm/drm_plane_helper.h> | 44 | #include <drm/drm_plane_helper.h> |
| @@ -32,10 +32,10 @@ · 31 unmodified lines | |||
| 32 | #include <linux/pwm.h> | 32 | #include <linux/pwm.h> |
| 33 | #include <linux/sched/clock.h> | 33 | #include <linux/sched/clock.h> |
| 34 | 34 | ||
| 35 | #include <drm/dp/drm_dp_dual_mode_helper.h> | ||
| 36 | #include <drm/dp/drm_dp_mst_helper.h> | ||
| 35 | #include <drm/drm_atomic.h> | 37 | #include <drm/drm_atomic.h> |
| 36 | #include <drm/drm_crtc.h> | 38 | #include <drm/drm_crtc.h> |
| 37 | #include <drm/drm_dp_dual_mode_helper.h> | ||
| 38 | #include <drm/drm_dp_mst_helper.h> | ||
| 39 | #include <drm/drm_dsc.h> | 39 | #include <drm/drm_dsc.h> |
| 40 | #include <drm/drm_encoder.h> | 40 | #include <drm/drm_encoder.h> |
| 41 | #include <drm/drm_fb_helper.h> | 41 | #include <drm/drm_fb_helper.h> |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | #include <drm/drm_atomic_helper.h> | 37 | #include <drm/drm_atomic_helper.h> |
| 38 | #include <drm/drm_crtc.h> | 38 | #include <drm/drm_crtc.h> |
| 39 | #include <drm/drm_dp_helper.h> | 39 | #include <drm/dp/drm_dp_helper.h> |
| 40 | #include <drm/drm_edid.h> | 40 | #include <drm/drm_edid.h> |
| 41 | #include <drm/drm_probe_helper.h> | 41 | #include <drm/drm_probe_helper.h> |
| 42 | 42 | ||
| @@ -6,8 +6,8 @@ · 5 unmodified lines | |||
| 6 | * Sean Paul <seanpaul@chromium.org> | 6 | * Sean Paul <seanpaul@chromium.org> |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <drm/drm_dp_helper.h> | 9 | #include <drm/dp/drm_dp_helper.h> |
| 10 | #include <drm/drm_dp_mst_helper.h> | 10 | #include <drm/dp/drm_dp_mst_helper.h> |
| 11 | #include <drm/drm_hdcp.h> | 11 | #include <drm/drm_hdcp.h> |
| 12 | #include <drm/drm_print.h> | 12 | #include <drm/drm_print.h> |
| 13 | 13 | ||
| @@ -6,7 +6,7 @@ · 5 unmodified lines | |||
| 6 | #ifndef __INTEL_DP_LINK_TRAINING_H__ | 6 | #ifndef __INTEL_DP_LINK_TRAINING_H__ |
| 7 | #define __INTEL_DP_LINK_TRAINING_H__ | 7 | #define __INTEL_DP_LINK_TRAINING_H__ |
| 8 | 8 | ||
| 9 | #include <drm/drm_dp_helper.h> | 9 | #include <drm/dp/drm_dp_helper.h> |
| 10 | 10 | ||
| 11 | struct intel_crtc_state; | 11 | struct intel_crtc_state; |
| 12 | struct intel_dp; | 12 | struct intel_dp; |
| @@ -730,7 +730,7 @@ intel_hdmi_compute_avi_infoframe(struct intel_encoder *encoder, · 729 unmodified lines | |||
| 730 | else | 730 | else |
| 731 | frame->colorspace = HDMI_COLORSPACE_RGB; | 731 | frame->colorspace = HDMI_COLORSPACE_RGB; |
| 732 | 732 | ||
| 733 | drm_hdmi_avi_infoframe_colorspace(frame, conn_state); | 733 | drm_hdmi_avi_infoframe_colorimetry(frame, conn_state); |
| 734 | 734 | ||
| 735 | /* nonsense combination */ | 735 | /* nonsense combination */ |
| 736 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && | 736 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && |
| @@ -1912,7 +1912,7 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector, · 1175 unmodified lines | |||
| 1912 | if (ycbcr420_output) | 1912 | if (ycbcr420_output) |
| 1913 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; | 1913 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_36; |
| 1914 | else | 1914 | else |
| 1915 | return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_36; | 1915 | return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36; |
| 1916 | case 10: | 1916 | case 10: |
| 1917 | if (!has_hdmi_sink) | 1917 | if (!has_hdmi_sink) |
| 1918 | return false; | 1918 | return false; |
| @@ -1920,7 +1920,7 @@ static bool intel_hdmi_sink_bpc_possible(struct drm_connector *connector, · 1 unmodified line | |||
| 1920 | if (ycbcr420_output) | 1920 | if (ycbcr420_output) |
| 1921 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; | 1921 | return hdmi->y420_dc_modes & DRM_EDID_YCBCR420_DC_30; |
| 1922 | else | 1922 | else |
| 1923 | return info->edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30; | 1923 | return info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30; |
| 1924 | case 8: | 1924 | case 8: |
| 1925 | return true; | 1925 | return true; |
| 1926 | default: | 1926 | default: |
| @@ -24,7 +24,7 @@ · 23 unmodified lines | |||
| 24 | */ | 24 | */ |
| 25 | 25 | ||
| 26 | #include <drm/drm_atomic_helper.h> | 26 | #include <drm/drm_atomic_helper.h> |
| 27 | #include <drm/drm_dp_dual_mode_helper.h> | 27 | #include <drm/dp/drm_dp_dual_mode_helper.h> |
| 28 | #include <drm/drm_edid.h> | 28 | #include <drm/drm_edid.h> |
| 29 | 29 | ||
| 30 | #include "intel_de.h" | 30 | #include "intel_de.h" |
| @@ -537,7 +537,7 @@ void lspcon_set_infoframes(struct intel_encoder *encoder, · 506 unmodified lines | |||
| 537 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; | 537 | frame.avi.colorspace = HDMI_COLORSPACE_RGB; |
| 538 | 538 | ||
| 539 | /* Set the Colorspace as per the HDMI spec */ | 539 | /* Set the Colorspace as per the HDMI spec */ |
| 540 | drm_hdmi_avi_infoframe_colorspace(&frame.avi, conn_state); | 540 | drm_hdmi_avi_infoframe_colorimetry(&frame.avi, conn_state); |
| 541 | 541 | ||
| 542 | /* nonsense combination */ | 542 | /* nonsense combination */ |
| 543 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && | 543 | drm_WARN_ON(encoder->base.dev, crtc_state->limited_color_range && |
| @@ -1,466 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | /* | ||
| 3 | * Copyright © 2021 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/kmemleak.h> | ||
| 7 | #include <linux/sizes.h> | ||
| 8 | |||
| 9 | #include "i915_buddy.h" | ||
| 10 | |||
| 11 | #include "i915_gem.h" | ||
| 12 | #include "i915_utils.h" | ||
| 13 | |||
| 14 | static struct kmem_cache *slab_blocks; | ||
| 15 | |||
| 16 | static struct i915_buddy_block *i915_block_alloc(struct i915_buddy_mm *mm, | ||
| 17 | struct i915_buddy_block *parent, | ||
| 18 | unsigned int order, | ||
| 19 | u64 offset) | ||
| 20 | { | ||
| 21 | struct i915_buddy_block *block; | ||
| 22 | |||
| 23 | GEM_BUG_ON(order > I915_BUDDY_MAX_ORDER); | ||
| 24 | |||
| 25 | block = kmem_cache_zalloc(slab_blocks, GFP_KERNEL); | ||
| 26 | if (!block) | ||
| 27 | return NULL; | ||
| 28 | |||
| 29 | block->header = offset; | ||
| 30 | block->header |= order; | ||
| 31 | block->parent = parent; | ||
| 32 | |||
| 33 | GEM_BUG_ON(block->header & I915_BUDDY_HEADER_UNUSED); | ||
| 34 | return block; | ||
| 35 | } | ||
| 36 | |||
| 37 | static void i915_block_free(struct i915_buddy_mm *mm, | ||
| 38 | struct i915_buddy_block *block) | ||
| 39 | { | ||
| 40 | kmem_cache_free(slab_blocks, block); | ||
| 41 | } | ||
| 42 | |||
| 43 | static void mark_allocated(struct i915_buddy_block *block) | ||
| 44 | { | ||
| 45 | block->header &= ~I915_BUDDY_HEADER_STATE; | ||
| 46 | block->header |= I915_BUDDY_ALLOCATED; | ||
| 47 | |||
| 48 | list_del(&block->link); | ||
| 49 | } | ||
| 50 | |||
| 51 | static void mark_free(struct i915_buddy_mm *mm, | ||
| 52 | struct i915_buddy_block *block) | ||
| 53 | { | ||
| 54 | block->header &= ~I915_BUDDY_HEADER_STATE; | ||
| 55 | block->header |= I915_BUDDY_FREE; | ||
| 56 | |||
| 57 | list_add(&block->link, | ||
| 58 | &mm->free_list[i915_buddy_block_order(block)]); | ||
| 59 | } | ||
| 60 | |||
| 61 | static void mark_split(struct i915_buddy_block *block) | ||
| 62 | { | ||
| 63 | block->header &= ~I915_BUDDY_HEADER_STATE; | ||
| 64 | block->header |= I915_BUDDY_SPLIT; | ||
| 65 | |||
| 66 | list_del(&block->link); | ||
| 67 | } | ||
| 68 | |||
| 69 | int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size) | ||
| 70 | { | ||
| 71 | unsigned int i; | ||
| 72 | u64 offset; | ||
| 73 | |||
| 74 | if (size < chunk_size) | ||
| 75 | return -EINVAL; | ||
| 76 | |||
| 77 | if (chunk_size < PAGE_SIZE) | ||
| 78 | return -EINVAL; | ||
| 79 | |||
| 80 | if (!is_power_of_2(chunk_size)) | ||
| 81 | return -EINVAL; | ||
| 82 | |||
| 83 | size = round_down(size, chunk_size); | ||
| 84 | |||
| 85 | mm->size = size; | ||
| 86 | mm->avail = size; | ||
| 87 | mm->chunk_size = chunk_size; | ||
| 88 | mm->max_order = ilog2(size) - ilog2(chunk_size); | ||
| 89 | |||
| 90 | GEM_BUG_ON(mm->max_order > I915_BUDDY_MAX_ORDER); | ||
| 91 | |||
| 92 | mm->free_list = kmalloc_array(mm->max_order + 1, | ||
| 93 | sizeof(struct list_head), | ||
| 94 | GFP_KERNEL); | ||
| 95 | if (!mm->free_list) | ||
| 96 | return -ENOMEM; | ||
| 97 | |||
| 98 | for (i = 0; i <= mm->max_order; ++i) | ||
| 99 | INIT_LIST_HEAD(&mm->free_list[i]); | ||
| 100 | |||
| 101 | mm->n_roots = hweight64(size); | ||
| 102 | |||
| 103 | mm->roots = kmalloc_array(mm->n_roots, | ||
| 104 | sizeof(struct i915_buddy_block *), | ||
| 105 | GFP_KERNEL); | ||
| 106 | if (!mm->roots) | ||
| 107 | goto out_free_list; | ||
| 108 | |||
| 109 | offset = 0; | ||
| 110 | i = 0; | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Split into power-of-two blocks, in case we are given a size that is | ||
| 114 | * not itself a power-of-two. | ||
| 115 | */ | ||
| 116 | do { | ||
| 117 | struct i915_buddy_block *root; | ||
| 118 | unsigned int order; | ||
| 119 | u64 root_size; | ||
| 120 | |||
| 121 | root_size = rounddown_pow_of_two(size); | ||
| 122 | order = ilog2(root_size) - ilog2(chunk_size); | ||
| 123 | |||
| 124 | root = i915_block_alloc(mm, NULL, order, offset); | ||
| 125 | if (!root) | ||
| 126 | goto out_free_roots; | ||
| 127 | |||
| 128 | mark_free(mm, root); | ||
| 129 | |||
| 130 | GEM_BUG_ON(i > mm->max_order); | ||
| 131 | GEM_BUG_ON(i915_buddy_block_size(mm, root) < chunk_size); | ||
| 132 | |||
| 133 | mm->roots[i] = root; | ||
| 134 | |||
| 135 | offset += root_size; | ||
| 136 | size -= root_size; | ||
| 137 | i++; | ||
| 138 | } while (size); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | |||
| 142 | out_free_roots: | ||
| 143 | while (i--) | ||
| 144 | i915_block_free(mm, mm->roots[i]); | ||
| 145 | kfree(mm->roots); | ||
| 146 | out_free_list: | ||
| 147 | kfree(mm->free_list); | ||
| 148 | return -ENOMEM; | ||
| 149 | } | ||
| 150 | |||
| 151 | void i915_buddy_fini(struct i915_buddy_mm *mm) | ||
| 152 | { | ||
| 153 | int i; | ||
| 154 | |||
| 155 | for (i = 0; i < mm->n_roots; ++i) { | ||
| 156 | GEM_WARN_ON(!i915_buddy_block_is_free(mm->roots[i])); | ||
| 157 | i915_block_free(mm, mm->roots[i]); | ||
| 158 | } | ||
| 159 | |||
| 160 | GEM_WARN_ON(mm->avail != mm->size); | ||
| 161 | |||
| 162 | kfree(mm->roots); | ||
| 163 | kfree(mm->free_list); | ||
| 164 | } | ||
| 165 | |||
| 166 | static int split_block(struct i915_buddy_mm *mm, | ||
| 167 | struct i915_buddy_block *block) | ||
| 168 | { | ||
| 169 | unsigned int block_order = i915_buddy_block_order(block) - 1; | ||
| 170 | u64 offset = i915_buddy_block_offset(block); | ||
| 171 | |||
| 172 | GEM_BUG_ON(!i915_buddy_block_is_free(block)); | ||
| 173 | GEM_BUG_ON(!i915_buddy_block_order(block)); | ||
| 174 | |||
| 175 | block->left = i915_block_alloc(mm, block, block_order, offset); | ||
| 176 | if (!block->left) | ||
| 177 | return -ENOMEM; | ||
| 178 | |||
| 179 | block->right = i915_block_alloc(mm, block, block_order, | ||
| 180 | offset + (mm->chunk_size << block_order)); | ||
| 181 | if (!block->right) { | ||
| 182 | i915_block_free(mm, block->left); | ||
| 183 | return -ENOMEM; | ||
| 184 | } | ||
| 185 | |||
| 186 | mark_free(mm, block->left); | ||
| 187 | mark_free(mm, block->right); | ||
| 188 | |||
| 189 | mark_split(block); | ||
| 190 | |||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static struct i915_buddy_block * | ||
| 195 | get_buddy(struct i915_buddy_block *block) | ||
| 196 | { | ||
| 197 | struct i915_buddy_block *parent; | ||
| 198 | |||
| 199 | parent = block->parent; | ||
| 200 | if (!parent) | ||
| 201 | return NULL; | ||
| 202 | |||
| 203 | if (parent->left == block) | ||
| 204 | return parent->right; | ||
| 205 | |||
| 206 | return parent->left; | ||
| 207 | } | ||
| 208 | |||
| 209 | static void __i915_buddy_free(struct i915_buddy_mm *mm, | ||
| 210 | struct i915_buddy_block *block) | ||
| 211 | { | ||
| 212 | struct i915_buddy_block *parent; | ||
| 213 | |||
| 214 | while ((parent = block->parent)) { | ||
| 215 | struct i915_buddy_block *buddy; | ||
| 216 | |||
| 217 | buddy = get_buddy(block); | ||
| 218 | |||
| 219 | if (!i915_buddy_block_is_free(buddy)) | ||
| 220 | break; | ||
| 221 | |||
| 222 | list_del(&buddy->link); | ||
| 223 | |||
| 224 | i915_block_free(mm, block); | ||
| 225 | i915_block_free(mm, buddy); | ||
| 226 | |||
| 227 | block = parent; | ||
| 228 | } | ||
| 229 | |||
| 230 | mark_free(mm, block); | ||
| 231 | } | ||
| 232 | |||
| 233 | void i915_buddy_free(struct i915_buddy_mm *mm, | ||
| 234 | struct i915_buddy_block *block) | ||
| 235 | { | ||
| 236 | GEM_BUG_ON(!i915_buddy_block_is_allocated(block)); | ||
| 237 | mm->avail += i915_buddy_block_size(mm, block); | ||
| 238 | __i915_buddy_free(mm, block); | ||
| 239 | } | ||
| 240 | |||
| 241 | void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects) | ||
| 242 | { | ||
| 243 | struct i915_buddy_block *block, *on; | ||
| 244 | |||
| 245 | list_for_each_entry_safe(block, on, objects, link) { | ||
| 246 | i915_buddy_free(mm, block); | ||
| 247 | cond_resched(); | ||
| 248 | } | ||
| 249 | INIT_LIST_HEAD(objects); | ||
| 250 | } | ||
| 251 | |||
| 252 | /* | ||
| 253 | * Allocate power-of-two block. The order value here translates to: | ||
| 254 | * | ||
| 255 | * 0 = 2^0 * mm->chunk_size | ||
| 256 | * 1 = 2^1 * mm->chunk_size | ||
| 257 | * 2 = 2^2 * mm->chunk_size | ||
| 258 | * ... | ||
| 259 | */ | ||
| 260 | struct i915_buddy_block * | ||
| 261 | i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order) | ||
| 262 | { | ||
| 263 | struct i915_buddy_block *block = NULL; | ||
| 264 | unsigned int i; | ||
| 265 | int err; | ||
| 266 | |||
| 267 | for (i = order; i <= mm->max_order; ++i) { | ||
| 268 | block = list_first_entry_or_null(&mm->free_list[i], | ||
| 269 | struct i915_buddy_block, | ||
| 270 | link); | ||
| 271 | if (block) | ||
| 272 | break; | ||
| 273 | } | ||
| 274 | |||
| 275 | if (!block) | ||
| 276 | return ERR_PTR(-ENOSPC); | ||
| 277 | |||
| 278 | GEM_BUG_ON(!i915_buddy_block_is_free(block)); | ||
| 279 | |||
| 280 | while (i != order) { | ||
| 281 | err = split_block(mm, block); | ||
| 282 | if (unlikely(err)) | ||
| 283 | goto out_free; | ||
| 284 | |||
| 285 | /* Go low */ | ||
| 286 | block = block->left; | ||
| 287 | i--; | ||
| 288 | } | ||
| 289 | |||
| 290 | mark_allocated(block); | ||
| 291 | mm->avail -= i915_buddy_block_size(mm, block); | ||
| 292 | kmemleak_update_trace(block); | ||
| 293 | return block; | ||
| 294 | |||
| 295 | out_free: | ||
| 296 | if (i != order) | ||
| 297 | __i915_buddy_free(mm, block); | ||
| 298 | return ERR_PTR(err); | ||
| 299 | } | ||
| 300 | |||
| 301 | static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) | ||
| 302 | { | ||
| 303 | return s1 <= e2 && e1 >= s2; | ||
| 304 | } | ||
| 305 | |||
| 306 | static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) | ||
| 307 | { | ||
| 308 | return s1 <= s2 && e1 >= e2; | ||
| 309 | } | ||
| 310 | |||
| 311 | /* | ||
| 312 | * Allocate range. Note that it's safe to chain together multiple alloc_ranges | ||
| 313 | * with the same blocks list. | ||
| 314 | * | ||
| 315 | * Intended for pre-allocating portions of the address space, for example to | ||
| 316 | * reserve a block for the initial framebuffer or similar, hence the expectation | ||
| 317 | * here is that i915_buddy_alloc() is still the main vehicle for | ||
| 318 | * allocations, so if that's not the case then the drm_mm range allocator is | ||
| 319 | * probably a much better fit, and so you should probably go use that instead. | ||
| 320 | */ | ||
| 321 | int i915_buddy_alloc_range(struct i915_buddy_mm *mm, | ||
| 322 | struct list_head *blocks, | ||
| 323 | u64 start, u64 size) | ||
| 324 | { | ||
| 325 | struct i915_buddy_block *block; | ||
| 326 | struct i915_buddy_block *buddy; | ||
| 327 | LIST_HEAD(allocated); | ||
| 328 | LIST_HEAD(dfs); | ||
| 329 | u64 end; | ||
| 330 | int err; | ||
| 331 | int i; | ||
| 332 | |||
| 333 | if (size < mm->chunk_size) | ||
| 334 | return -EINVAL; | ||
| 335 | |||
| 336 | if (!IS_ALIGNED(size | start, mm->chunk_size)) | ||
| 337 | return -EINVAL; | ||
| 338 | |||
| 339 | if (range_overflows(start, size, mm->size)) | ||
| 340 | return -EINVAL; | ||
| 341 | |||
| 342 | for (i = 0; i < mm->n_roots; ++i) | ||
| 343 | list_add_tail(&mm->roots[i]->tmp_link, &dfs); | ||
| 344 | |||
| 345 | end = start + size - 1; | ||
| 346 | |||
| 347 | do { | ||
| 348 | u64 block_start; | ||
| 349 | u64 block_end; | ||
| 350 | |||
| 351 | block = list_first_entry_or_null(&dfs, | ||
| 352 | struct i915_buddy_block, | ||
| 353 | tmp_link); | ||
| 354 | if (!block) | ||
| 355 | break; | ||
| 356 | |||
| 357 | list_del(&block->tmp_link); | ||
| 358 | |||
| 359 | block_start = i915_buddy_block_offset(block); | ||
| 360 | block_end = block_start + i915_buddy_block_size(mm, block) - 1; | ||
| 361 | |||
| 362 | if (!overlaps(start, end, block_start, block_end)) | ||
| 363 | continue; | ||
| 364 | |||
| 365 | if (i915_buddy_block_is_allocated(block)) { | ||
| 366 | err = -ENOSPC; | ||
| 367 | goto err_free; | ||
| 368 | } | ||
| 369 | |||
| 370 | if (contains(start, end, block_start, block_end)) { | ||
| 371 | if (!i915_buddy_block_is_free(block)) { | ||
| 372 | err = -ENOSPC; | ||
| 373 | goto err_free; | ||
| 374 | } | ||
| 375 | |||
| 376 | mark_allocated(block); | ||
| 377 | mm->avail -= i915_buddy_block_size(mm, block); | ||
| 378 | list_add_tail(&block->link, &allocated); | ||
| 379 | continue; | ||
| 380 | } | ||
| 381 | |||
| 382 | if (!i915_buddy_block_is_split(block)) { | ||
| 383 | err = split_block(mm, block); | ||
| 384 | if (unlikely(err)) | ||
| 385 | goto err_undo; | ||
| 386 | } | ||
| 387 | |||
| 388 | list_add(&block->right->tmp_link, &dfs); | ||
| 389 | list_add(&block->left->tmp_link, &dfs); | ||
| 390 | } while (1); | ||
| 391 | |||
| 392 | list_splice_tail(&allocated, blocks); | ||
| 393 | return 0; | ||
| 394 | |||
| 395 | err_undo: | ||
| 396 | /* | ||
| 397 | * We really don't want to leave around a bunch of split blocks, since | ||
| 398 | * bigger is better, so make sure we merge everything back before we | ||
| 399 | * free the allocated blocks. | ||
| 400 | */ | ||
| 401 | buddy = get_buddy(block); | ||
| 402 | if (buddy && | ||
| 403 | (i915_buddy_block_is_free(block) && | ||
| 404 | i915_buddy_block_is_free(buddy))) | ||
| 405 | __i915_buddy_free(mm, block); | ||
| 406 | |||
| 407 | err_free: | ||
| 408 | i915_buddy_free_list(mm, &allocated); | ||
| 409 | return err; | ||
| 410 | } | ||
| 411 | |||
| 412 | void i915_buddy_block_print(struct i915_buddy_mm *mm, | ||
| 413 | struct i915_buddy_block *block, | ||
| 414 | struct drm_printer *p) | ||
| 415 | { | ||
| 416 | u64 start = i915_buddy_block_offset(block); | ||
| 417 | u64 size = i915_buddy_block_size(mm, block); | ||
| 418 | |||
| 419 | drm_printf(p, "%#018llx-%#018llx: %llu\n", start, start + size, size); | ||
| 420 | } | ||
| 421 | |||
| 422 | void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p) | ||
| 423 | { | ||
| 424 | int order; | ||
| 425 | |||
| 426 | drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", | ||
| 427 | mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); | ||
| 428 | |||
| 429 | for (order = mm->max_order; order >= 0; order--) { | ||
| 430 | struct i915_buddy_block *block; | ||
| 431 | u64 count = 0, free; | ||
| 432 | |||
| 433 | list_for_each_entry(block, &mm->free_list[order], link) { | ||
| 434 | GEM_BUG_ON(!i915_buddy_block_is_free(block)); | ||
| 435 | count++; | ||
| 436 | } | ||
| 437 | |||
| 438 | drm_printf(p, "order-%d ", order); | ||
| 439 | |||
| 440 | free = count * (mm->chunk_size << order); | ||
| 441 | if (free < SZ_1M) | ||
| 442 | drm_printf(p, "free: %lluKiB", free >> 10); | ||
| 443 | else | ||
| 444 | drm_printf(p, "free: %lluMiB", free >> 20); | ||
| 445 | |||
| 446 | drm_printf(p, ", pages: %llu\n", count); | ||
| 447 | } | ||
| 448 | } | ||
| 449 | |||
| 450 | #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) | ||
| 451 | #include "selftests/i915_buddy.c" | ||
| 452 | #endif | ||
| 453 | |||
| 454 | void i915_buddy_module_exit(void) | ||
| 455 | { | ||
| 456 | kmem_cache_destroy(slab_blocks); | ||
| 457 | } | ||
| 458 | |||
| 459 | int __init i915_buddy_module_init(void) | ||
| 460 | { | ||
| 461 | slab_blocks = KMEM_CACHE(i915_buddy_block, 0); | ||
| 462 | if (!slab_blocks) | ||
| 463 | return -ENOMEM; | ||
| 464 | |||
| 465 | return 0; | ||
| 466 | } | ||
| @@ -1,143 +0,0 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2021 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef __I915_BUDDY_H__ | ||
| 7 | #define __I915_BUDDY_H__ | ||
| 8 | |||
| 9 | #include <linux/bitops.h> | ||
| 10 | #include <linux/list.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | |||
| 13 | #include <drm/drm_print.h> | ||
| 14 | |||
| 15 | struct i915_buddy_block { | ||
| 16 | #define I915_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) | ||
| 17 | #define I915_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) | ||
| 18 | #define I915_BUDDY_ALLOCATED (1 << 10) | ||
| 19 | #define I915_BUDDY_FREE (2 << 10) | ||
| 20 | #define I915_BUDDY_SPLIT (3 << 10) | ||
| 21 | /* Free to be used, if needed in the future */ | ||
| 22 | #define I915_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6) | ||
| 23 | #define I915_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0) | ||
| 24 | u64 header; | ||
| 25 | |||
| 26 | struct i915_buddy_block *left; | ||
| 27 | struct i915_buddy_block *right; | ||
| 28 | struct i915_buddy_block *parent; | ||
| 29 | |||
| 30 | void *private; /* owned by creator */ | ||
| 31 | |||
| 32 | /* | ||
| 33 | * While the block is allocated by the user through i915_buddy_alloc*, | ||
| 34 | * the user has ownership of the link, for example to maintain within | ||
| 35 | * a list, if so desired. As soon as the block is freed with | ||
| 36 | * i915_buddy_free* ownership is given back to the mm. | ||
| 37 | */ | ||
| 38 | struct list_head link; | ||
| 39 | struct list_head tmp_link; | ||
| 40 | }; | ||
| 41 | |||
| 42 | /* Order-zero must be at least PAGE_SIZE */ | ||
| 43 | #define I915_BUDDY_MAX_ORDER (63 - PAGE_SHIFT) | ||
| 44 | |||
| 45 | /* | ||
| 46 | * Binary Buddy System. | ||
| 47 | * | ||
| 48 | * Locking should be handled by the user, a simple mutex around | ||
| 49 | * i915_buddy_alloc* and i915_buddy_free* should suffice. | ||
| 50 | */ | ||
| 51 | struct i915_buddy_mm { | ||
| 52 | /* Maintain a free list for each order. */ | ||
| 53 | struct list_head *free_list; | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Maintain explicit binary tree(s) to track the allocation of the | ||
| 57 | * address space. This gives us a simple way of finding a buddy block | ||
| 58 | * and performing the potentially recursive merge step when freeing a | ||
| 59 | * block. Nodes are either allocated or free, in which case they will | ||
| 60 | * also exist on the respective free list. | ||
| 61 | */ | ||
| 62 | struct i915_buddy_block **roots; | ||
| 63 | |||
| 64 | /* | ||
| 65 | * Anything from here is public, and remains static for the lifetime of | ||
| 66 | * the mm. Everything above is considered do-not-touch. | ||
| 67 | */ | ||
| 68 | unsigned int n_roots; | ||
| 69 | unsigned int max_order; | ||
| 70 | |||
| 71 | /* Must be at least PAGE_SIZE */ | ||
| 72 | u64 chunk_size; | ||
| 73 | u64 size; | ||
| 74 | u64 avail; | ||
| 75 | }; | ||
| 76 | |||
| 77 | static inline u64 | ||
| 78 | i915_buddy_block_offset(struct i915_buddy_block *block) | ||
| 79 | { | ||
| 80 | return block->header & I915_BUDDY_HEADER_OFFSET; | ||
| 81 | } | ||
| 82 | |||
| 83 | static inline unsigned int | ||
| 84 | i915_buddy_block_order(struct i915_buddy_block *block) | ||
| 85 | { | ||
| 86 | return block->header & I915_BUDDY_HEADER_ORDER; | ||
| 87 | } | ||
| 88 | |||
| 89 | static inline unsigned int | ||
| 90 | i915_buddy_block_state(struct i915_buddy_block *block) | ||
| 91 | { | ||
| 92 | return block->header & I915_BUDDY_HEADER_STATE; | ||
| 93 | } | ||
| 94 | |||
| 95 | static inline bool | ||
| 96 | i915_buddy_block_is_allocated(struct i915_buddy_block *block) | ||
| 97 | { | ||
| 98 | return i915_buddy_block_state(block) == I915_BUDDY_ALLOCATED; | ||
| 99 | } | ||
| 100 | |||
| 101 | static inline bool | ||
| 102 | i915_buddy_block_is_free(struct i915_buddy_block *block) | ||
| 103 | { | ||
| 104 | return i915_buddy_block_state(block) == I915_BUDDY_FREE; | ||
| 105 | } | ||
| 106 | |||
| 107 | static inline bool | ||
| 108 | i915_buddy_block_is_split(struct i915_buddy_block *block) | ||
| 109 | { | ||
| 110 | return i915_buddy_block_state(block) == I915_BUDDY_SPLIT; | ||
| 111 | } | ||
| 112 | |||
| 113 | static inline u64 | ||
| 114 | i915_buddy_block_size(struct i915_buddy_mm *mm, | ||
| 115 | struct i915_buddy_block *block) | ||
| 116 | { | ||
| 117 | return mm->chunk_size << i915_buddy_block_order(block); | ||
| 118 | } | ||
| 119 | |||
| 120 | int i915_buddy_init(struct i915_buddy_mm *mm, u64 size, u64 chunk_size); | ||
| 121 | |||
| 122 | void i915_buddy_fini(struct i915_buddy_mm *mm); | ||
| 123 | |||
| 124 | struct i915_buddy_block * | ||
| 125 | i915_buddy_alloc(struct i915_buddy_mm *mm, unsigned int order); | ||
| 126 | |||
| 127 | int i915_buddy_alloc_range(struct i915_buddy_mm *mm, | ||
| 128 | struct list_head *blocks, | ||
| 129 | u64 start, u64 size); | ||
| 130 | |||
| 131 | void i915_buddy_free(struct i915_buddy_mm *mm, struct i915_buddy_block *block); | ||
| 132 | |||
| 133 | void i915_buddy_free_list(struct i915_buddy_mm *mm, struct list_head *objects); | ||
| 134 | |||
| 135 | void i915_buddy_print(struct i915_buddy_mm *mm, struct drm_printer *p); | ||
| 136 | void i915_buddy_block_print(struct i915_buddy_mm *mm, | ||
| 137 | struct i915_buddy_block *block, | ||
| 138 | struct drm_printer *p); | ||
| 139 | |||
| 140 | void i915_buddy_module_exit(void); | ||
| 141 | int i915_buddy_module_init(void); | ||
| 142 | |||
| 143 | #endif | ||
| @@ -9,7 +9,6 @@ · 8 unmodified lines | |||
| 9 | #include "gem/i915_gem_context.h" | 9 | #include "gem/i915_gem_context.h" |
| 10 | #include "gem/i915_gem_object.h" | 10 | #include "gem/i915_gem_object.h" |
| 11 | #include "i915_active.h" | 11 | #include "i915_active.h" |
| 12 | #include "i915_buddy.h" | ||
| 13 | #include "i915_params.h" | 12 | #include "i915_params.h" |
| 14 | #include "i915_pci.h" | 13 | #include "i915_pci.h" |
| 15 | #include "i915_perf.h" | 14 | #include "i915_perf.h" |
| @@ -50,8 +49,6 @@ static const struct { · 34 unmodified lines | |||
| 50 | { .init = i915_check_nomodeset }, | 49 | { .init = i915_check_nomodeset }, |
| 51 | { .init = i915_active_module_init, | 50 | { .init = i915_active_module_init, |
| 52 | .exit = i915_active_module_exit }, | 51 | .exit = i915_active_module_exit }, |
| 53 | { .init = i915_buddy_module_init, | ||
| 54 | .exit = i915_buddy_module_exit }, | ||
| 55 | { .init = i915_context_module_init, | 52 | { .init = i915_context_module_init, |
| 56 | .exit = i915_context_module_exit }, | 53 | .exit = i915_context_module_exit }, |
| 57 | { .init = i915_gem_context_module_init, | 54 | { .init = i915_gem_context_module_init, |
| @@ -5,10 +5,9 @@ · 4 unmodified lines | |||
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include "i915_scatterlist.h" | 7 | #include "i915_scatterlist.h" |
| 8 | |||
| 9 | #include "i915_buddy.h" | ||
| 10 | #include "i915_ttm_buddy_manager.h" | 8 | #include "i915_ttm_buddy_manager.h" |
| 11 | 9 | ||
| 10 | #include <drm/drm_buddy.h> | ||
| 12 | #include <drm/drm_mm.h> | 11 | #include <drm/drm_mm.h> |
| 13 | 12 | ||
| 14 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| @@ -153,9 +152,9 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, · 138 unmodified lines | |||
| 153 | struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); | 152 | struct i915_ttm_buddy_resource *bman_res = to_ttm_buddy_resource(res); |
| 154 | const u64 size = res->num_pages << PAGE_SHIFT; | 153 | const u64 size = res->num_pages << PAGE_SHIFT; |
| 155 | const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE); | 154 | const u64 max_segment = rounddown(UINT_MAX, PAGE_SIZE); |
| 156 | struct i915_buddy_mm *mm = bman_res->mm; | 155 | struct drm_buddy *mm = bman_res->mm; |
| 157 | struct list_head *blocks = &bman_res->blocks; | 156 | struct list_head *blocks = &bman_res->blocks; |
| 158 | struct i915_buddy_block *block; | 157 | struct drm_buddy_block *block; |
| 159 | struct i915_refct_sgt *rsgt; | 158 | struct i915_refct_sgt *rsgt; |
| 160 | struct scatterlist *sg; | 159 | struct scatterlist *sg; |
| 161 | struct sg_table *st; | 160 | struct sg_table *st; |
| @@ -181,8 +180,8 @@ struct i915_refct_sgt *i915_rsgt_from_buddy_resource(struct ttm_resource *res, · 19 unmodified lines | |||
| 181 | list_for_each_entry(block, blocks, link) { | 180 | list_for_each_entry(block, blocks, link) { |
| 182 | u64 block_size, offset; | 181 | u64 block_size, offset; |
| 183 | 182 | ||
| 184 | block_size = min_t(u64, size, i915_buddy_block_size(mm, block)); | 183 | block_size = min_t(u64, size, drm_buddy_block_size(mm, block)); |
| 185 | offset = i915_buddy_block_offset(block); | 184 | offset = drm_buddy_block_offset(block); |
| 186 | 185 | ||
| 187 | while (block_size) { | 186 | while (block_size) { |
| 188 | u64 len; | 187 | u64 len; |
| @@ -8,14 +8,15 @@ · 7 unmodified lines | |||
| 8 | #include <drm/ttm/ttm_bo_driver.h> | 8 | #include <drm/ttm/ttm_bo_driver.h> |
| 9 | #include <drm/ttm/ttm_placement.h> | 9 | #include <drm/ttm/ttm_placement.h> |
| 10 | 10 | ||
| 11 | #include <drm/drm_buddy.h> | ||
| 12 | |||
| 11 | #include "i915_ttm_buddy_manager.h" | 13 | #include "i915_ttm_buddy_manager.h" |
| 12 | 14 | ||
| 13 | #include "i915_buddy.h" | ||
| 14 | #include "i915_gem.h" | 15 | #include "i915_gem.h" |
| 15 | 16 | ||
| 16 | struct i915_ttm_buddy_manager { | 17 | struct i915_ttm_buddy_manager { |
| 17 | struct ttm_resource_manager manager; | 18 | struct ttm_resource_manager manager; |
| 18 | struct i915_buddy_mm mm; | 19 | struct drm_buddy mm; |
| 19 | struct list_head reserved; | 20 | struct list_head reserved; |
| 20 | struct mutex lock; | 21 | struct mutex lock; |
| 21 | u64 default_page_size; | 22 | u64 default_page_size; |
| @@ -34,7 +35,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 12 unmodified lines | |||
| 34 | { | 35 | { |
| 35 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); | 36 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 36 | struct i915_ttm_buddy_resource *bman_res; | 37 | struct i915_ttm_buddy_resource *bman_res; |
| 37 | struct i915_buddy_mm *mm = &bman->mm; | 38 | struct drm_buddy *mm = &bman->mm; |
| 38 | unsigned long n_pages; | 39 | unsigned long n_pages; |
| 39 | unsigned int min_order; | 40 | unsigned int min_order; |
| 40 | u64 min_page_size; | 41 | u64 min_page_size; |
| @@ -73,7 +74,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 32 unmodified lines | |||
| 73 | n_pages = size >> ilog2(mm->chunk_size); | 74 | n_pages = size >> ilog2(mm->chunk_size); |
| 74 | 75 | ||
| 75 | do { | 76 | do { |
| 76 | struct i915_buddy_block *block; | 77 | struct drm_buddy_block *block; |
| 77 | unsigned int order; | 78 | unsigned int order; |
| 78 | 79 | ||
| 79 | order = fls(n_pages) - 1; | 80 | order = fls(n_pages) - 1; |
| @@ -82,7 +83,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 2 unmodified lines | |||
| 82 | 83 | ||
| 83 | do { | 84 | do { |
| 84 | mutex_lock(&bman->lock); | 85 | mutex_lock(&bman->lock); |
| 85 | block = i915_buddy_alloc(mm, order); | 86 | block = drm_buddy_alloc_blocks(mm, order); |
| 86 | mutex_unlock(&bman->lock); | 87 | mutex_unlock(&bman->lock); |
| 87 | if (!IS_ERR(block)) | 88 | if (!IS_ERR(block)) |
| 88 | break; | 89 | break; |
| @@ -106,9 +107,10 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, · 17 unmodified lines | |||
| 106 | 107 | ||
| 107 | err_free_blocks: | 108 | err_free_blocks: |
| 108 | mutex_lock(&bman->lock); | 109 | mutex_lock(&bman->lock); |
| 109 | i915_buddy_free_list(mm, &bman_res->blocks); | 110 | drm_buddy_free_list(mm, &bman_res->blocks); |
| 110 | mutex_unlock(&bman->lock); | 111 | mutex_unlock(&bman->lock); |
| 111 | err_free_res: | 112 | err_free_res: |
| 113 | ttm_resource_fini(man, &bman_res->base); | ||
| 112 | kfree(bman_res); | 114 | kfree(bman_res); |
| 113 | return err; | 115 | return err; |
| 114 | } | 116 | } |
| @@ -120,9 +122,10 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man, · 5 unmodified lines | |||
| 120 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); | 122 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 121 | 123 | ||
| 122 | mutex_lock(&bman->lock); | 124 | mutex_lock(&bman->lock); |
| 123 | i915_buddy_free_list(&bman->mm, &bman_res->blocks); | 125 | drm_buddy_free_list(&bman->mm, &bman_res->blocks); |
| 124 | mutex_unlock(&bman->lock); | 126 | mutex_unlock(&bman->lock); |
| 125 | 127 | ||
| 128 | ttm_resource_fini(man, res); | ||
| 126 | kfree(bman_res); | 129 | kfree(bman_res); |
| 127 | } | 130 | } |
| 128 | 131 | ||
| @@ -130,17 +133,17 @@ static void i915_ttm_buddy_man_debug(struct ttm_resource_manager *man, · 1 unmodified line | |||
| 130 | struct drm_printer *printer) | 133 | struct drm_printer *printer) |
| 131 | { | 134 | { |
| 132 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); | 135 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 133 | struct i915_buddy_block *block; | 136 | struct drm_buddy_block *block; |
| 134 | 137 | ||
| 135 | mutex_lock(&bman->lock); | 138 | mutex_lock(&bman->lock); |
| 136 | drm_printf(printer, "default_page_size: %lluKiB\n", | 139 | drm_printf(printer, "default_page_size: %lluKiB\n", |
| 137 | bman->default_page_size >> 10); | 140 | bman->default_page_size >> 10); |
| 138 | 141 | ||
| 139 | i915_buddy_print(&bman->mm, printer); | 142 | drm_buddy_print(&bman->mm, printer); |
| 140 | 143 | ||
| 141 | drm_printf(printer, "reserved:\n"); | 144 | drm_printf(printer, "reserved:\n"); |
| 142 | list_for_each_entry(block, &bman->reserved, link) | 145 | list_for_each_entry(block, &bman->reserved, link) |
| 143 | i915_buddy_block_print(&bman->mm, block, printer); | 146 | drm_buddy_block_print(&bman->mm, block, printer); |
| 144 | mutex_unlock(&bman->lock); | 147 | mutex_unlock(&bman->lock); |
| 145 | } | 148 | } |
| 146 | 149 | ||
| @@ -190,7 +193,7 @@ int i915_ttm_buddy_man_init(struct ttm_device *bdev, · 43 unmodified lines | |||
| 190 | if (!bman) | 193 | if (!bman) |
| 191 | return -ENOMEM; | 194 | return -ENOMEM; |
| 192 | 195 | ||
| 193 | err = i915_buddy_init(&bman->mm, size, chunk_size); | 196 | err = drm_buddy_init(&bman->mm, size, chunk_size); |
| 194 | if (err) | 197 | if (err) |
| 195 | goto err_free_bman; | 198 | goto err_free_bman; |
| 196 | 199 | ||
| @@ -202,7 +205,7 @@ int i915_ttm_buddy_man_init(struct ttm_device *bdev, · 5 unmodified lines | |||
| 202 | man = &bman->manager; | 205 | man = &bman->manager; |
| 203 | man->use_tt = use_tt; | 206 | man->use_tt = use_tt; |
| 204 | man->func = &i915_ttm_buddy_manager_func; | 207 | man->func = &i915_ttm_buddy_manager_func; |
| 205 | ttm_resource_manager_init(man, bman->mm.size >> PAGE_SHIFT); | 208 | ttm_resource_manager_init(man, bdev, bman->mm.size >> PAGE_SHIFT); |
| 206 | 209 | ||
| 207 | ttm_resource_manager_set_used(man, true); | 210 | ttm_resource_manager_set_used(man, true); |
| 208 | ttm_set_driver_manager(bdev, type, man); | 211 | ttm_set_driver_manager(bdev, type, man); |
| @@ -228,7 +231,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) · 19 unmodified lines | |||
| 228 | { | 231 | { |
| 229 | struct ttm_resource_manager *man = ttm_manager_type(bdev, type); | 232 | struct ttm_resource_manager *man = ttm_manager_type(bdev, type); |
| 230 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); | 233 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 231 | struct i915_buddy_mm *mm = &bman->mm; | 234 | struct drm_buddy *mm = &bman->mm; |
| 232 | int ret; | 235 | int ret; |
| 233 | 236 | ||
| 234 | ttm_resource_manager_set_used(man, false); | 237 | ttm_resource_manager_set_used(man, false); |
| @@ -240,8 +243,8 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) · 5 unmodified lines | |||
| 240 | ttm_set_driver_manager(bdev, type, NULL); | 243 | ttm_set_driver_manager(bdev, type, NULL); |
| 241 | 244 | ||
| 242 | mutex_lock(&bman->lock); | 245 | mutex_lock(&bman->lock); |
| 243 | i915_buddy_free_list(mm, &bman->reserved); | 246 | drm_buddy_free_list(mm, &bman->reserved); |
| 244 | i915_buddy_fini(mm); | 247 | drm_buddy_fini(mm); |
| 245 | mutex_unlock(&bman->lock); | 248 | mutex_unlock(&bman->lock); |
| 246 | 249 | ||
| 247 | ttm_resource_manager_cleanup(man); | 250 | ttm_resource_manager_cleanup(man); |
| @@ -264,11 +267,11 @@ int i915_ttm_buddy_man_reserve(struct ttm_resource_manager *man, · 16 unmodified lines | |||
| 264 | u64 start, u64 size) | 267 | u64 start, u64 size) |
| 265 | { | 268 | { |
| 266 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); | 269 | struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); |
| 267 | struct i915_buddy_mm *mm = &bman->mm; | 270 | struct drm_buddy *mm = &bman->mm; |
| 268 | int ret; | 271 | int ret; |
| 269 | 272 | ||
| 270 | mutex_lock(&bman->lock); | 273 | mutex_lock(&bman->lock); |
| 271 | ret = i915_buddy_alloc_range(mm, &bman->reserved, start, size); | 274 | ret = drm_buddy_alloc_range(mm, &bman->reserved, start, size); |
| 272 | mutex_unlock(&bman->lock); | 275 | mutex_unlock(&bman->lock); |
| 273 | 276 | ||
| 274 | return ret; | 277 | return ret; |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | struct ttm_device; | 14 | struct ttm_device; |
| 15 | struct ttm_resource_manager; | 15 | struct ttm_resource_manager; |
| 16 | struct i915_buddy_mm; | 16 | struct drm_buddy; |
| 17 | 17 | ||
| 18 | /** | 18 | /** |
| 19 | * struct i915_ttm_buddy_resource | 19 | * struct i915_ttm_buddy_resource |
| @@ -28,7 +28,7 @@ struct i915_buddy_mm; · 8 unmodified lines | |||
| 28 | struct i915_ttm_buddy_resource { | 28 | struct i915_ttm_buddy_resource { |
| 29 | struct ttm_resource base; | 29 | struct ttm_resource base; |
| 30 | struct list_head blocks; | 30 | struct list_head blocks; |
| 31 | struct i915_buddy_mm *mm; | 31 | struct drm_buddy *mm; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | /** | 34 | /** |
| @@ -1,787 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | /* | ||
| 3 | * Copyright © 2019 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/prime_numbers.h> | ||
| 7 | |||
| 8 | #include "../i915_selftest.h" | ||
| 9 | #include "i915_random.h" | ||
| 10 | |||
| 11 | static void __igt_dump_block(struct i915_buddy_mm *mm, | ||
| 12 | struct i915_buddy_block *block, | ||
| 13 | bool buddy) | ||
| 14 | { | ||
| 15 | pr_err("block info: header=%llx, state=%u, order=%d, offset=%llx size=%llx root=%s buddy=%s\n", | ||
| 16 | block->header, | ||
| 17 | i915_buddy_block_state(block), | ||
| 18 | i915_buddy_block_order(block), | ||
| 19 | i915_buddy_block_offset(block), | ||
| 20 | i915_buddy_block_size(mm, block), | ||
| 21 | yesno(!block->parent), | ||
| 22 | yesno(buddy)); | ||
| 23 | } | ||
| 24 | |||
| 25 | static void igt_dump_block(struct i915_buddy_mm *mm, | ||
| 26 | struct i915_buddy_block *block) | ||
| 27 | { | ||
| 28 | struct i915_buddy_block *buddy; | ||
| 29 | |||
| 30 | __igt_dump_block(mm, block, false); | ||
| 31 | |||
| 32 | buddy = get_buddy(block); | ||
| 33 | if (buddy) | ||
| 34 | __igt_dump_block(mm, buddy, true); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int igt_check_block(struct i915_buddy_mm *mm, | ||
| 38 | struct i915_buddy_block *block) | ||
| 39 | { | ||
| 40 | struct i915_buddy_block *buddy; | ||
| 41 | unsigned int block_state; | ||
| 42 | u64 block_size; | ||
| 43 | u64 offset; | ||
| 44 | int err = 0; | ||
| 45 | |||
| 46 | block_state = i915_buddy_block_state(block); | ||
| 47 | |||
| 48 | if (block_state != I915_BUDDY_ALLOCATED && | ||
| 49 | block_state != I915_BUDDY_FREE && | ||
| 50 | block_state != I915_BUDDY_SPLIT) { | ||
| 51 | pr_err("block state mismatch\n"); | ||
| 52 | err = -EINVAL; | ||
| 53 | } | ||
| 54 | |||
| 55 | block_size = i915_buddy_block_size(mm, block); | ||
| 56 | offset = i915_buddy_block_offset(block); | ||
| 57 | |||
| 58 | if (block_size < mm->chunk_size) { | ||
| 59 | pr_err("block size smaller than min size\n"); | ||
| 60 | err = -EINVAL; | ||
| 61 | } | ||
| 62 | |||
| 63 | if (!is_power_of_2(block_size)) { | ||
| 64 | pr_err("block size not power of two\n"); | ||
| 65 | err = -EINVAL; | ||
| 66 | } | ||
| 67 | |||
| 68 | if (!IS_ALIGNED(block_size, mm->chunk_size)) { | ||
| 69 | pr_err("block size not aligned to min size\n"); | ||
| 70 | err = -EINVAL; | ||
| 71 | } | ||
| 72 | |||
| 73 | if (!IS_ALIGNED(offset, mm->chunk_size)) { | ||
| 74 | pr_err("block offset not aligned to min size\n"); | ||
| 75 | err = -EINVAL; | ||
| 76 | } | ||
| 77 | |||
| 78 | if (!IS_ALIGNED(offset, block_size)) { | ||
| 79 | pr_err("block offset not aligned to block size\n"); | ||
| 80 | err = -EINVAL; | ||
| 81 | } | ||
| 82 | |||
| 83 | buddy = get_buddy(block); | ||
| 84 | |||
| 85 | if (!buddy && block->parent) { | ||
| 86 | pr_err("buddy has gone fishing\n"); | ||
| 87 | err = -EINVAL; | ||
| 88 | } | ||
| 89 | |||
| 90 | if (buddy) { | ||
| 91 | if (i915_buddy_block_offset(buddy) != (offset ^ block_size)) { | ||
| 92 | pr_err("buddy has wrong offset\n"); | ||
| 93 | err = -EINVAL; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (i915_buddy_block_size(mm, buddy) != block_size) { | ||
| 97 | pr_err("buddy size mismatch\n"); | ||
| 98 | err = -EINVAL; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (i915_buddy_block_state(buddy) == block_state && | ||
| 102 | block_state == I915_BUDDY_FREE) { | ||
| 103 | pr_err("block and its buddy are free\n"); | ||
| 104 | err = -EINVAL; | ||
| 105 | } | ||
| 106 | } | ||
| 107 | |||
| 108 | return err; | ||
| 109 | } | ||
| 110 | |||
| 111 | static int igt_check_blocks(struct i915_buddy_mm *mm, | ||
| 112 | struct list_head *blocks, | ||
| 113 | u64 expected_size, | ||
| 114 | bool is_contiguous) | ||
| 115 | { | ||
| 116 | struct i915_buddy_block *block; | ||
| 117 | struct i915_buddy_block *prev; | ||
| 118 | u64 total; | ||
| 119 | int err = 0; | ||
| 120 | |||
| 121 | block = NULL; | ||
| 122 | prev = NULL; | ||
| 123 | total = 0; | ||
| 124 | |||
| 125 | list_for_each_entry(block, blocks, link) { | ||
| 126 | err = igt_check_block(mm, block); | ||
| 127 | |||
| 128 | if (!i915_buddy_block_is_allocated(block)) { | ||
| 129 | pr_err("block not allocated\n"), | ||
| 130 | err = -EINVAL; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (is_contiguous && prev) { | ||
| 134 | u64 prev_block_size; | ||
| 135 | u64 prev_offset; | ||
| 136 | u64 offset; | ||
| 137 | |||
| 138 | prev_offset = i915_buddy_block_offset(prev); | ||
| 139 | prev_block_size = i915_buddy_block_size(mm, prev); | ||
| 140 | offset = i915_buddy_block_offset(block); | ||
| 141 | |||
| 142 | if (offset != (prev_offset + prev_block_size)) { | ||
| 143 | pr_err("block offset mismatch\n"); | ||
| 144 | err = -EINVAL; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | |||
| 148 | if (err) | ||
| 149 | break; | ||
| 150 | |||
| 151 | total += i915_buddy_block_size(mm, block); | ||
| 152 | prev = block; | ||
| 153 | } | ||
| 154 | |||
| 155 | if (!err) { | ||
| 156 | if (total != expected_size) { | ||
| 157 | pr_err("size mismatch, expected=%llx, found=%llx\n", | ||
| 158 | expected_size, total); | ||
| 159 | err = -EINVAL; | ||
| 160 | } | ||
| 161 | return err; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (prev) { | ||
| 165 | pr_err("prev block, dump:\n"); | ||
| 166 | igt_dump_block(mm, prev); | ||
| 167 | } | ||
| 168 | |||
| 169 | pr_err("bad block, dump:\n"); | ||
| 170 | igt_dump_block(mm, block); | ||
| 171 | |||
| 172 | return err; | ||
| 173 | } | ||
| 174 | |||
| 175 | static int igt_check_mm(struct i915_buddy_mm *mm) | ||
| 176 | { | ||
| 177 | struct i915_buddy_block *root; | ||
| 178 | struct i915_buddy_block *prev; | ||
| 179 | unsigned int i; | ||
| 180 | u64 total; | ||
| 181 | int err = 0; | ||
| 182 | |||
| 183 | if (!mm->n_roots) { | ||
| 184 | pr_err("n_roots is zero\n"); | ||
| 185 | return -EINVAL; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (mm->n_roots != hweight64(mm->size)) { | ||
| 189 | pr_err("n_roots mismatch, n_roots=%u, expected=%lu\n", | ||
| 190 | mm->n_roots, hweight64(mm->size)); | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | |||
| 194 | root = NULL; | ||
| 195 | prev = NULL; | ||
| 196 | total = 0; | ||
| 197 | |||
| 198 | for (i = 0; i < mm->n_roots; ++i) { | ||
| 199 | struct i915_buddy_block *block; | ||
| 200 | unsigned int order; | ||
| 201 | |||
| 202 | root = mm->roots[i]; | ||
| 203 | if (!root) { | ||
| 204 | pr_err("root(%u) is NULL\n", i); | ||
| 205 | err = -EINVAL; | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | |||
| 209 | err = igt_check_block(mm, root); | ||
| 210 | |||
| 211 | if (!i915_buddy_block_is_free(root)) { | ||
| 212 | pr_err("root not free\n"); | ||
| 213 | err = -EINVAL; | ||
| 214 | } | ||
| 215 | |||
| 216 | order = i915_buddy_block_order(root); | ||
| 217 | |||
| 218 | if (!i) { | ||
| 219 | if (order != mm->max_order) { | ||
| 220 | pr_err("max order root missing\n"); | ||
| 221 | err = -EINVAL; | ||
| 222 | } | ||
| 223 | } | ||
| 224 | |||
| 225 | if (prev) { | ||
| 226 | u64 prev_block_size; | ||
| 227 | u64 prev_offset; | ||
| 228 | u64 offset; | ||
| 229 | |||
| 230 | prev_offset = i915_buddy_block_offset(prev); | ||
| 231 | prev_block_size = i915_buddy_block_size(mm, prev); | ||
| 232 | offset = i915_buddy_block_offset(root); | ||
| 233 | |||
| 234 | if (offset != (prev_offset + prev_block_size)) { | ||
| 235 | pr_err("root offset mismatch\n"); | ||
| 236 | err = -EINVAL; | ||
| 237 | } | ||
| 238 | } | ||
| 239 | |||
| 240 | block = list_first_entry_or_null(&mm->free_list[order], | ||
| 241 | struct i915_buddy_block, | ||
| 242 | link); | ||
| 243 | if (block != root) { | ||
| 244 | pr_err("root mismatch at order=%u\n", order); | ||
| 245 | err = -EINVAL; | ||
| 246 | } | ||
| 247 | |||
| 248 | if (err) | ||
| 249 | break; | ||
| 250 | |||
| 251 | prev = root; | ||
| 252 | total += i915_buddy_block_size(mm, root); | ||
| 253 | } | ||
| 254 | |||
| 255 | if (!err) { | ||
| 256 | if (total != mm->size) { | ||
| 257 | pr_err("expected mm size=%llx, found=%llx\n", mm->size, | ||
| 258 | total); | ||
| 259 | err = -EINVAL; | ||
| 260 | } | ||
| 261 | return err; | ||
| 262 | } | ||
| 263 | |||
| 264 | if (prev) { | ||
| 265 | pr_err("prev root(%u), dump:\n", i - 1); | ||
| 266 | igt_dump_block(mm, prev); | ||
| 267 | } | ||
| 268 | |||
| 269 | if (root) { | ||
| 270 | pr_err("bad root(%u), dump:\n", i); | ||
| 271 | igt_dump_block(mm, root); | ||
| 272 | } | ||
| 273 | |||
| 274 | return err; | ||
| 275 | } | ||
| 276 | |||
| 277 | static void igt_mm_config(u64 *size, u64 *chunk_size) | ||
| 278 | { | ||
| 279 | I915_RND_STATE(prng); | ||
| 280 | u32 s, ms; | ||
| 281 | |||
| 282 | /* Nothing fancy, just try to get an interesting bit pattern */ | ||
| 283 | |||
| 284 | prandom_seed_state(&prng, i915_selftest.random_seed); | ||
| 285 | |||
| 286 | /* Let size be a random number of pages up to 8 GB (2M pages) */ | ||
| 287 | s = 1 + i915_prandom_u32_max_state((BIT(33 - 12)) - 1, &prng); | ||
| 288 | /* Let the chunk size be a random power of 2 less than size */ | ||
| 289 | ms = BIT(i915_prandom_u32_max_state(ilog2(s), &prng)); | ||
| 290 | /* Round size down to the chunk size */ | ||
| 291 | s &= -ms; | ||
| 292 | |||
| 293 | /* Convert from pages to bytes */ | ||
| 294 | *chunk_size = (u64)ms << 12; | ||
| 295 | *size = (u64)s << 12; | ||
| 296 | } | ||
| 297 | |||
| 298 | static int igt_buddy_alloc_smoke(void *arg) | ||
| 299 | { | ||
| 300 | struct i915_buddy_mm mm; | ||
| 301 | IGT_TIMEOUT(end_time); | ||
| 302 | I915_RND_STATE(prng); | ||
| 303 | u64 chunk_size; | ||
| 304 | u64 mm_size; | ||
| 305 | int *order; | ||
| 306 | int err, i; | ||
| 307 | |||
| 308 | igt_mm_config(&mm_size, &chunk_size); | ||
| 309 | |||
| 310 | pr_info("buddy_init with size=%llx, chunk_size=%llx\n", mm_size, chunk_size); | ||
| 311 | |||
| 312 | err = i915_buddy_init(&mm, mm_size, chunk_size); | ||
| 313 | if (err) { | ||
| 314 | pr_err("buddy_init failed(%d)\n", err); | ||
| 315 | return err; | ||
| 316 | } | ||
| 317 | |||
| 318 | order = i915_random_order(mm.max_order + 1, &prng); | ||
| 319 | if (!order) | ||
| 320 | goto out_fini; | ||
| 321 | |||
| 322 | for (i = 0; i <= mm.max_order; ++i) { | ||
| 323 | struct i915_buddy_block *block; | ||
| 324 | int max_order = order[i]; | ||
| 325 | bool timeout = false; | ||
| 326 | LIST_HEAD(blocks); | ||
| 327 | int order; | ||
| 328 | u64 total; | ||
| 329 | |||
| 330 | err = igt_check_mm(&mm); | ||
| 331 | if (err) { | ||
| 332 | pr_err("pre-mm check failed, abort\n"); | ||
| 333 | break; | ||
| 334 | } | ||
| 335 | |||
| 336 | pr_info("filling from max_order=%u\n", max_order); | ||
| 337 | |||
| 338 | order = max_order; | ||
| 339 | total = 0; | ||
| 340 | |||
| 341 | do { | ||
| 342 | retry: | ||
| 343 | block = i915_buddy_alloc(&mm, order); | ||
| 344 | if (IS_ERR(block)) { | ||
| 345 | err = PTR_ERR(block); | ||
| 346 | if (err == -ENOMEM) { | ||
| 347 | pr_info("buddy_alloc hit -ENOMEM with order=%d\n", | ||
| 348 | order); | ||
| 349 | } else { | ||
| 350 | if (order--) { | ||
| 351 | err = 0; | ||
| 352 | goto retry; | ||
| 353 | } | ||
| 354 | |||
| 355 | pr_err("buddy_alloc with order=%d failed(%d)\n", | ||
| 356 | order, err); | ||
| 357 | } | ||
| 358 | |||
| 359 | break; | ||
| 360 | } | ||
| 361 | |||
| 362 | list_add_tail(&block->link, &blocks); | ||
| 363 | |||
| 364 | if (i915_buddy_block_order(block) != order) { | ||
| 365 | pr_err("buddy_alloc order mismatch\n"); | ||
| 366 | err = -EINVAL; | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | |||
| 370 | total += i915_buddy_block_size(&mm, block); | ||
| 371 | |||
| 372 | if (__igt_timeout(end_time, NULL)) { | ||
| 373 | timeout = true; | ||
| 374 | break; | ||
| 375 | } | ||
| 376 | } while (total < mm.size); | ||
| 377 | |||
| 378 | if (!err) | ||
| 379 | err = igt_check_blocks(&mm, &blocks, total, false); | ||
| 380 | |||
| 381 | i915_buddy_free_list(&mm, &blocks); | ||
| 382 | |||
| 383 | if (!err) { | ||
| 384 | err = igt_check_mm(&mm); | ||
| 385 | if (err) | ||
| 386 | pr_err("post-mm check failed\n"); | ||
| 387 | } | ||
| 388 | |||
| 389 | if (err || timeout) | ||
| 390 | break; | ||
| 391 | |||
| 392 | cond_resched(); | ||
| 393 | } | ||
| 394 | |||
| 395 | if (err == -ENOMEM) | ||
| 396 | err = 0; | ||
| 397 | |||
| 398 | kfree(order); | ||
| 399 | out_fini: | ||
| 400 | i915_buddy_fini(&mm); | ||
| 401 | |||
| 402 | return err; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int igt_buddy_alloc_pessimistic(void *arg) | ||
| 406 | { | ||
| 407 | const unsigned int max_order = 16; | ||
| 408 | struct i915_buddy_block *block, *bn; | ||
| 409 | struct i915_buddy_mm mm; | ||
| 410 | unsigned int order; | ||
| 411 | LIST_HEAD(blocks); | ||
| 412 | int err; | ||
| 413 | |||
| 414 | /* | ||
| 415 | * Create a pot-sized mm, then allocate one of each possible | ||
| 416 | * order within. This should leave the mm with exactly one | ||
| 417 | * page left. | ||
| 418 | */ | ||
| 419 | |||
| 420 | err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE); | ||
| 421 | if (err) { | ||
| 422 | pr_err("buddy_init failed(%d)\n", err); | ||
| 423 | return err; | ||
| 424 | } | ||
| 425 | GEM_BUG_ON(mm.max_order != max_order); | ||
| 426 | |||
| 427 | for (order = 0; order < max_order; order++) { | ||
| 428 | block = i915_buddy_alloc(&mm, order); | ||
| 429 | if (IS_ERR(block)) { | ||
| 430 | pr_info("buddy_alloc hit -ENOMEM with order=%d\n", | ||
| 431 | order); | ||
| 432 | err = PTR_ERR(block); | ||
| 433 | goto err; | ||
| 434 | } | ||
| 435 | |||
| 436 | list_add_tail(&block->link, &blocks); | ||
| 437 | } | ||
| 438 | |||
| 439 | /* And now the last remaining block available */ | ||
| 440 | block = i915_buddy_alloc(&mm, 0); | ||
| 441 | if (IS_ERR(block)) { | ||
| 442 | pr_info("buddy_alloc hit -ENOMEM on final alloc\n"); | ||
| 443 | err = PTR_ERR(block); | ||
| 444 | goto err; | ||
| 445 | } | ||
| 446 | list_add_tail(&block->link, &blocks); | ||
| 447 | |||
| 448 | /* Should be completely full! */ | ||
| 449 | for (order = max_order; order--; ) { | ||
| 450 | block = i915_buddy_alloc(&mm, order); | ||
| 451 | if (!IS_ERR(block)) { | ||
| 452 | pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", | ||
| 453 | order); | ||
| 454 | list_add_tail(&block->link, &blocks); | ||
| 455 | err = -EINVAL; | ||
| 456 | goto err; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | block = list_last_entry(&blocks, typeof(*block), link); | ||
| 461 | list_del(&block->link); | ||
| 462 | i915_buddy_free(&mm, block); | ||
| 463 | |||
| 464 | /* As we free in increasing size, we make available larger blocks */ | ||
| 465 | order = 1; | ||
| 466 | list_for_each_entry_safe(block, bn, &blocks, link) { | ||
| 467 | list_del(&block->link); | ||
| 468 | i915_buddy_free(&mm, block); | ||
| 469 | |||
| 470 | block = i915_buddy_alloc(&mm, order); | ||
| 471 | if (IS_ERR(block)) { | ||
| 472 | pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", | ||
| 473 | order); | ||
| 474 | err = PTR_ERR(block); | ||
| 475 | goto err; | ||
| 476 | } | ||
| 477 | i915_buddy_free(&mm, block); | ||
| 478 | order++; | ||
| 479 | } | ||
| 480 | |||
| 481 | /* To confirm, now the whole mm should be available */ | ||
| 482 | block = i915_buddy_alloc(&mm, max_order); | ||
| 483 | if (IS_ERR(block)) { | ||
| 484 | pr_info("buddy_alloc (realloc) hit -ENOMEM with order=%d\n", | ||
| 485 | max_order); | ||
| 486 | err = PTR_ERR(block); | ||
| 487 | goto err; | ||
| 488 | } | ||
| 489 | i915_buddy_free(&mm, block); | ||
| 490 | |||
| 491 | err: | ||
| 492 | i915_buddy_free_list(&mm, &blocks); | ||
| 493 | i915_buddy_fini(&mm); | ||
| 494 | return err; | ||
| 495 | } | ||
| 496 | |||
| 497 | static int igt_buddy_alloc_optimistic(void *arg) | ||
| 498 | { | ||
| 499 | const int max_order = 16; | ||
| 500 | struct i915_buddy_block *block; | ||
| 501 | struct i915_buddy_mm mm; | ||
| 502 | LIST_HEAD(blocks); | ||
| 503 | int order; | ||
| 504 | int err; | ||
| 505 | |||
| 506 | /* | ||
| 507 | * Create a mm with one block of each order available, and | ||
| 508 | * try to allocate them all. | ||
| 509 | */ | ||
| 510 | |||
| 511 | err = i915_buddy_init(&mm, | ||
| 512 | PAGE_SIZE * ((1 << (max_order + 1)) - 1), | ||
| 513 | PAGE_SIZE); | ||
| 514 | if (err) { | ||
| 515 | pr_err("buddy_init failed(%d)\n", err); | ||
| 516 | return err; | ||
| 517 | } | ||
| 518 | GEM_BUG_ON(mm.max_order != max_order); | ||
| 519 | |||
| 520 | for (order = 0; order <= max_order; order++) { | ||
| 521 | block = i915_buddy_alloc(&mm, order); | ||
| 522 | if (IS_ERR(block)) { | ||
| 523 | pr_info("buddy_alloc hit -ENOMEM with order=%d\n", | ||
| 524 | order); | ||
| 525 | err = PTR_ERR(block); | ||
| 526 | goto err; | ||
| 527 | } | ||
| 528 | |||
| 529 | list_add_tail(&block->link, &blocks); | ||
| 530 | } | ||
| 531 | |||
| 532 | /* Should be completely full! */ | ||
| 533 | block = i915_buddy_alloc(&mm, 0); | ||
| 534 | if (!IS_ERR(block)) { | ||
| 535 | pr_info("buddy_alloc unexpectedly succeeded, it should be full!"); | ||
| 536 | list_add_tail(&block->link, &blocks); | ||
| 537 | err = -EINVAL; | ||
| 538 | goto err; | ||
| 539 | } | ||
| 540 | |||
| 541 | err: | ||
| 542 | i915_buddy_free_list(&mm, &blocks); | ||
| 543 | i915_buddy_fini(&mm); | ||
| 544 | return err; | ||
| 545 | } | ||
| 546 | |||
| 547 | static int igt_buddy_alloc_pathological(void *arg) | ||
| 548 | { | ||
| 549 | const int max_order = 16; | ||
| 550 | struct i915_buddy_block *block; | ||
| 551 | struct i915_buddy_mm mm; | ||
| 552 | LIST_HEAD(blocks); | ||
| 553 | LIST_HEAD(holes); | ||
| 554 | int order, top; | ||
| 555 | int err; | ||
| 556 | |||
| 557 | /* | ||
| 558 | * Create a pot-sized mm, then allocate one of each possible | ||
| 559 | * order within. This should leave the mm with exactly one | ||
| 560 | * page left. Free the largest block, then whittle down again. | ||
| 561 | * Eventually we will have a fully 50% fragmented mm. | ||
| 562 | */ | ||
| 563 | |||
| 564 | err = i915_buddy_init(&mm, PAGE_SIZE << max_order, PAGE_SIZE); | ||
| 565 | if (err) { | ||
| 566 | pr_err("buddy_init failed(%d)\n", err); | ||
| 567 | return err; | ||
| 568 | } | ||
| 569 | GEM_BUG_ON(mm.max_order != max_order); | ||
| 570 | |||
| 571 | for (top = max_order; top; top--) { | ||
| 572 | /* Make room by freeing the largest allocated block */ | ||
| 573 | block = list_first_entry_or_null(&blocks, typeof(*block), link); | ||
| 574 | if (block) { | ||
| 575 | list_del(&block->link); | ||
| 576 | i915_buddy_free(&mm, block); | ||
| 577 | } | ||
| 578 | |||
| 579 | for (order = top; order--; ) { | ||
| 580 | block = i915_buddy_alloc(&mm, order); | ||
| 581 | if (IS_ERR(block)) { | ||
| 582 | pr_info("buddy_alloc hit -ENOMEM with order=%d, top=%d\n", | ||
| 583 | order, top); | ||
| 584 | err = PTR_ERR(block); | ||
| 585 | goto err; | ||
| 586 | } | ||
| 587 | list_add_tail(&block->link, &blocks); | ||
| 588 | } | ||
| 589 | |||
| 590 | /* There should be one final page for this sub-allocation */ | ||
| 591 | block = i915_buddy_alloc(&mm, 0); | ||
| 592 | if (IS_ERR(block)) { | ||
| 593 | pr_info("buddy_alloc hit -ENOMEM for hole\n"); | ||
| 594 | err = PTR_ERR(block); | ||
| 595 | goto err; | ||
| 596 | } | ||
| 597 | list_add_tail(&block->link, &holes); | ||
| 598 | |||
| 599 | block = i915_buddy_alloc(&mm, top); | ||
| 600 | if (!IS_ERR(block)) { | ||
| 601 | pr_info("buddy_alloc unexpectedly succeeded at top-order %d/%d, it should be full!", | ||
| 602 | top, max_order); | ||
| 603 | list_add_tail(&block->link, &blocks); | ||
| 604 | err = -EINVAL; | ||
| 605 | goto err; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | i915_buddy_free_list(&mm, &holes); | ||
| 610 | |||
| 611 | /* Nothing larger than blocks of chunk_size now available */ | ||
| 612 | for (order = 1; order <= max_order; order++) { | ||
| 613 | block = i915_buddy_alloc(&mm, order); | ||
| 614 | if (!IS_ERR(block)) { | ||
| 615 | pr_info("buddy_alloc unexpectedly succeeded at order %d, it should be full!", | ||
| 616 | order); | ||
| 617 | list_add_tail(&block->link, &blocks); | ||
| 618 | err = -EINVAL; | ||
| 619 | goto err; | ||
| 620 | } | ||
| 621 | } | ||
| 622 | |||
| 623 | err: | ||
| 624 | list_splice_tail(&holes, &blocks); | ||
| 625 | i915_buddy_free_list(&mm, &blocks); | ||
| 626 | i915_buddy_fini(&mm); | ||
| 627 | return err; | ||
| 628 | } | ||
| 629 | |||
| 630 | static int igt_buddy_alloc_range(void *arg) | ||
| 631 | { | ||
| 632 | struct i915_buddy_mm mm; | ||
| 633 | unsigned long page_num; | ||
| 634 | LIST_HEAD(blocks); | ||
| 635 | u64 chunk_size; | ||
| 636 | u64 offset; | ||
| 637 | u64 size; | ||
| 638 | u64 rem; | ||
| 639 | int err; | ||
| 640 | |||
| 641 | igt_mm_config(&size, &chunk_size); | ||
| 642 | |||
| 643 | pr_info("buddy_init with size=%llx, chunk_size=%llx\n", size, chunk_size); | ||
| 644 | |||
| 645 | err = i915_buddy_init(&mm, size, chunk_size); | ||
| 646 | if (err) { | ||
| 647 | pr_err("buddy_init failed(%d)\n", err); | ||
| 648 | return err; | ||
| 649 | } | ||
| 650 | |||
| 651 | err = igt_check_mm(&mm); | ||
| 652 | if (err) { | ||
| 653 | pr_err("pre-mm check failed, abort, abort, abort!\n"); | ||
| 654 | goto err_fini; | ||
| 655 | } | ||
| 656 | |||
| 657 | rem = mm.size; | ||
| 658 | offset = 0; | ||
| 659 | |||
| 660 | for_each_prime_number_from(page_num, 1, ULONG_MAX - 1) { | ||
| 661 | struct i915_buddy_block *block; | ||
| 662 | LIST_HEAD(tmp); | ||
| 663 | |||
| 664 | size = min(page_num * mm.chunk_size, rem); | ||
| 665 | |||
| 666 | err = i915_buddy_alloc_range(&mm, &tmp, offset, size); | ||
| 667 | if (err) { | ||
| 668 | if (err == -ENOMEM) { | ||
| 669 | pr_info("alloc_range hit -ENOMEM with size=%llx\n", | ||
| 670 | size); | ||
| 671 | } else { | ||
| 672 | pr_err("alloc_range with offset=%llx, size=%llx failed(%d)\n", | ||
| 673 | offset, size, err); | ||
| 674 | } | ||
| 675 | |||
| 676 | break; | ||
| 677 | } | ||
| 678 | |||
| 679 | block = list_first_entry_or_null(&tmp, | ||
| 680 | struct i915_buddy_block, | ||
| 681 | link); | ||
| 682 | if (!block) { | ||
| 683 | pr_err("alloc_range has no blocks\n"); | ||
| 684 | err = -EINVAL; | ||
| 685 | break; | ||
| 686 | } | ||
| 687 | |||
| 688 | if (i915_buddy_block_offset(block) != offset) { | ||
| 689 | pr_err("alloc_range start offset mismatch, found=%llx, expected=%llx\n", | ||
| 690 | i915_buddy_block_offset(block), offset); | ||
| 691 | err = -EINVAL; | ||
| 692 | } | ||
| 693 | |||
| 694 | if (!err) | ||
| 695 | err = igt_check_blocks(&mm, &tmp, size, true); | ||
| 696 | |||
| 697 | list_splice_tail(&tmp, &blocks); | ||
| 698 | |||
| 699 | if (err) | ||
| 700 | break; | ||
| 701 | |||
| 702 | offset += size; | ||
| 703 | |||
| 704 | rem -= size; | ||
| 705 | if (!rem) | ||
| 706 | break; | ||
| 707 | |||
| 708 | cond_resched(); | ||
| 709 | } | ||
| 710 | |||
| 711 | if (err == -ENOMEM) | ||
| 712 | err = 0; | ||
| 713 | |||
| 714 | i915_buddy_free_list(&mm, &blocks); | ||
| 715 | |||
| 716 | if (!err) { | ||
| 717 | err = igt_check_mm(&mm); | ||
| 718 | if (err) | ||
| 719 | pr_err("post-mm check failed\n"); | ||
| 720 | } | ||
| 721 | |||
| 722 | err_fini: | ||
| 723 | i915_buddy_fini(&mm); | ||
| 724 | |||
| 725 | return err; | ||
| 726 | } | ||
| 727 | |||
| 728 | static int igt_buddy_alloc_limit(void *arg) | ||
| 729 | { | ||
| 730 | struct i915_buddy_block *block; | ||
| 731 | struct i915_buddy_mm mm; | ||
| 732 | const u64 size = U64_MAX; | ||
| 733 | int err; | ||
| 734 | |||
| 735 | err = i915_buddy_init(&mm, size, PAGE_SIZE); | ||
| 736 | if (err) | ||
| 737 | return err; | ||
| 738 | |||
| 739 | if (mm.max_order != I915_BUDDY_MAX_ORDER) { | ||
| 740 | pr_err("mm.max_order(%d) != %d\n", | ||
| 741 | mm.max_order, I915_BUDDY_MAX_ORDER); | ||
| 742 | err = -EINVAL; | ||
| 743 | goto out_fini; | ||
| 744 | } | ||
| 745 | |||
| 746 | block = i915_buddy_alloc(&mm, mm.max_order); | ||
| 747 | if (IS_ERR(block)) { | ||
| 748 | err = PTR_ERR(block); | ||
| 749 | goto out_fini; | ||
| 750 | } | ||
| 751 | |||
| 752 | if (i915_buddy_block_order(block) != mm.max_order) { | ||
| 753 | pr_err("block order(%d) != %d\n", | ||
| 754 | i915_buddy_block_order(block), mm.max_order); | ||
| 755 | err = -EINVAL; | ||
| 756 | goto out_free; | ||
| 757 | } | ||
| 758 | |||
| 759 | if (i915_buddy_block_size(&mm, block) != | ||
| 760 | BIT_ULL(mm.max_order) * PAGE_SIZE) { | ||
| 761 | pr_err("block size(%llu) != %llu\n", | ||
| 762 | i915_buddy_block_size(&mm, block), | ||
| 763 | BIT_ULL(mm.max_order) * PAGE_SIZE); | ||
| 764 | err = -EINVAL; | ||
| 765 | goto out_free; | ||
| 766 | } | ||
| 767 | |||
| 768 | out_free: | ||
| 769 | i915_buddy_free(&mm, block); | ||
| 770 | out_fini: | ||
| 771 | i915_buddy_fini(&mm); | ||
| 772 | return err; | ||
| 773 | } | ||
| 774 | |||
| 775 | int i915_buddy_mock_selftests(void) | ||
| 776 | { | ||
| 777 | static const struct i915_subtest tests[] = { | ||
| 778 | SUBTEST(igt_buddy_alloc_pessimistic), | ||
| 779 | SUBTEST(igt_buddy_alloc_optimistic), | ||
| 780 | SUBTEST(igt_buddy_alloc_pathological), | ||
| 781 | SUBTEST(igt_buddy_alloc_smoke), | ||
| 782 | SUBTEST(igt_buddy_alloc_range), | ||
| 783 | SUBTEST(igt_buddy_alloc_limit), | ||
| 784 | }; | ||
| 785 | |||
| 786 | return i915_subtests(tests, NULL); | ||
| 787 | } | ||
| @@ -33,4 +33,3 @@ selftest(evict, i915_gem_evict_mock_selftests) · 32 unmodified lines | |||
| 33 | selftest(gtt, i915_gem_gtt_mock_selftests) | 33 | selftest(gtt, i915_gem_gtt_mock_selftests) |
| 34 | selftest(hugepages, i915_gem_huge_page_mock_selftests) | 34 | selftest(hugepages, i915_gem_huge_page_mock_selftests) |
| 35 | selftest(memory_region, intel_memory_region_mock_selftests) | 35 | selftest(memory_region, intel_memory_region_mock_selftests) |
| 36 | selftest(buddy, i915_buddy_mock_selftests) | ||
| @@ -6,6 +6,8 @@ · 5 unmodified lines | |||
| 6 | #include <linux/prime_numbers.h> | 6 | #include <linux/prime_numbers.h> |
| 7 | #include <linux/sort.h> | 7 | #include <linux/sort.h> |
| 8 | 8 | ||
| 9 | #include <drm/drm_buddy.h> | ||
| 10 | |||
| 9 | #include "../i915_selftest.h" | 11 | #include "../i915_selftest.h" |
| 10 | 12 | ||
| 11 | #include "mock_drm.h" | 13 | #include "mock_drm.h" |
| @@ -20,7 +22,6 @@ · 8 unmodified lines | |||
| 20 | #include "gt/intel_engine_pm.h" | 22 | #include "gt/intel_engine_pm.h" |
| 21 | #include "gt/intel_engine_user.h" | 23 | #include "gt/intel_engine_user.h" |
| 22 | #include "gt/intel_gt.h" | 24 | #include "gt/intel_gt.h" |
| 23 | #include "i915_buddy.h" | ||
| 24 | #include "gt/intel_migrate.h" | 25 | #include "gt/intel_migrate.h" |
| 25 | #include "i915_memcpy.h" | 26 | #include "i915_memcpy.h" |
| 26 | #include "i915_ttm_buddy_manager.h" | 27 | #include "i915_ttm_buddy_manager.h" |
| @@ -369,7 +370,7 @@ static int igt_mock_splintered_region(void *arg) · 342 unmodified lines | |||
| 369 | struct drm_i915_private *i915 = mem->i915; | 370 | struct drm_i915_private *i915 = mem->i915; |
| 370 | struct i915_ttm_buddy_resource *res; | 371 | struct i915_ttm_buddy_resource *res; |
| 371 | struct drm_i915_gem_object *obj; | 372 | struct drm_i915_gem_object *obj; |
| 372 | struct i915_buddy_mm *mm; | 373 | struct drm_buddy *mm; |
| 373 | unsigned int expected_order; | 374 | unsigned int expected_order; |
| 374 | LIST_HEAD(objects); | 375 | LIST_HEAD(objects); |
| 375 | u64 size; | 376 | u64 size; |
| @@ -454,8 +455,8 @@ static int igt_mock_max_segment(void *arg) · 78 unmodified lines | |||
| 454 | struct drm_i915_private *i915 = mem->i915; | 455 | struct drm_i915_private *i915 = mem->i915; |
| 455 | struct i915_ttm_buddy_resource *res; | 456 | struct i915_ttm_buddy_resource *res; |
| 456 | struct drm_i915_gem_object *obj; | 457 | struct drm_i915_gem_object *obj; |
| 457 | struct i915_buddy_block *block; | 458 | struct drm_buddy_block *block; |
| 458 | struct i915_buddy_mm *mm; | 459 | struct drm_buddy *mm; |
| 459 | struct list_head *blocks; | 460 | struct list_head *blocks; |
| 460 | struct scatterlist *sg; | 461 | struct scatterlist *sg; |
| 461 | LIST_HEAD(objects); | 462 | LIST_HEAD(objects); |
| @@ -485,8 +486,8 @@ static int igt_mock_max_segment(void *arg) · 23 unmodified lines | |||
| 485 | mm = res->mm; | 486 | mm = res->mm; |
| 486 | size = 0; | 487 | size = 0; |
| 487 | list_for_each_entry(block, blocks, link) { | 488 | list_for_each_entry(block, blocks, link) { |
| 488 | if (i915_buddy_block_size(mm, block) > size) | 489 | if (drm_buddy_block_size(mm, block) > size) |
| 489 | size = i915_buddy_block_size(mm, block); | 490 | size = drm_buddy_block_size(mm, block); |
| 490 | } | 491 | } |
| 491 | if (size < max_segment) { | 492 | if (size < max_segment) { |
| 492 | pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n", | 493 | pr_err("%s: Failed to create a huge contiguous block [> %u], largest block %lld\n", |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | #include <linux/module.h> | 6 | #include <linux/module.h> |
| 7 | #include <linux/kernel.h> | 7 | #include <linux/kernel.h> |
| 8 | #include <linux/platform_device.h> | 8 | #include <linux/platform_device.h> |
| 9 | #include <drm/drm_module.h> | ||
| 9 | #include <drm/drm_of.h> | 10 | #include <drm/drm_of.h> |
| 10 | 11 | ||
| 11 | #include "dcss-dev.h" | 12 | #include "dcss-dev.h" |
| @@ -131,7 +132,7 @@ static struct platform_driver dcss_platform_driver = { · 119 unmodified lines | |||
| 131 | }, | 132 | }, |
| 132 | }; | 133 | }; |
| 133 | 134 | ||
| 134 | module_platform_driver(dcss_platform_driver); | 135 | drm_module_platform_driver(dcss_platform_driver); |
| 135 | 136 | ||
| 136 | MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>"); | 137 | MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@nxp.com>"); |
| 137 | MODULE_DESCRIPTION("DCSS driver for i.MX8MQ"); | 138 | MODULE_DESCRIPTION("DCSS driver for i.MX8MQ"); |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | 6 | ||
| 7 | #include "ingenic-drm.h" | 7 | #include "ingenic-drm.h" |
| 8 | 8 | ||
| 9 | #include <linux/bitfield.h> | ||
| 9 | #include <linux/component.h> | 10 | #include <linux/component.h> |
| 10 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
| 11 | #include <linux/dma-mapping.h> | 12 | #include <linux/dma-mapping.h> |
| @@ -49,6 +50,11 @@ struct ingenic_dma_hwdesc { · 37 unmodified lines | |||
| 49 | u32 addr; | 50 | u32 addr; |
| 50 | u32 id; | 51 | u32 id; |
| 51 | u32 cmd; | 52 | u32 cmd; |
| 53 | /* extended hw descriptor for jz4780 */ | ||
| 54 | u32 offsize; | ||
| 55 | u32 pagewidth; | ||
| 56 | u32 cpos; | ||
| 57 | u32 dessize; | ||
| 52 | } __aligned(16); | 58 | } __aligned(16); |
| 53 | 59 | ||
| 54 | struct ingenic_dma_hwdescs { | 60 | struct ingenic_dma_hwdescs { |
| @@ -60,6 +66,7 @@ struct jz_soc_info { · 5 unmodified lines | |||
| 60 | bool needs_dev_clk; | 66 | bool needs_dev_clk; |
| 61 | bool has_osd; | 67 | bool has_osd; |
| 62 | bool map_noncoherent; | 68 | bool map_noncoherent; |
| 69 | bool use_extended_hwdesc; | ||
| 63 | unsigned int max_width, max_height; | 70 | unsigned int max_width, max_height; |
| 64 | const u32 *formats_f0, *formats_f1; | 71 | const u32 *formats_f0, *formats_f1; |
| 65 | unsigned int num_formats_f0, num_formats_f1; | 72 | unsigned int num_formats_f0, num_formats_f1; |
| @@ -173,7 +180,6 @@ static const struct regmap_config ingenic_drm_regmap_config = { · 107 unmodified lines | |||
| 173 | .val_bits = 32, | 180 | .val_bits = 32, |
| 174 | .reg_stride = 4, | 181 | .reg_stride = 4, |
| 175 | 182 | ||
| 176 | .max_register = JZ_REG_LCD_SIZE1, | ||
| 177 | .writeable_reg = ingenic_drm_writeable_reg, | 183 | .writeable_reg = ingenic_drm_writeable_reg, |
| 178 | }; | 184 | }; |
| 179 | 185 | ||
| @@ -447,6 +453,9 @@ static int ingenic_drm_plane_atomic_check(struct drm_plane *plane, · 267 unmodified lines | |||
| 447 | if (!crtc) | 453 | if (!crtc) |
| 448 | return 0; | 454 | return 0; |
| 449 | 455 | ||
| 456 | if (plane == &priv->f0) | ||
| 457 | return -EINVAL; | ||
| 458 | |||
| 450 | crtc_state = drm_atomic_get_existing_crtc_state(state, | 459 | crtc_state = drm_atomic_get_existing_crtc_state(state, |
| 451 | crtc); | 460 | crtc); |
| 452 | if (WARN_ON(!crtc_state)) | 461 | if (WARN_ON(!crtc_state)) |
| @@ -663,6 +672,33 @@ static void ingenic_drm_plane_atomic_update(struct drm_plane *plane, · 210 unmodified lines | |||
| 663 | hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); | 672 | hwdesc->cmd = JZ_LCD_CMD_EOF_IRQ | (width * height * cpp / 4); |
| 664 | hwdesc->next = dma_hwdesc_addr(priv, next_id); | 673 | hwdesc->next = dma_hwdesc_addr(priv, next_id); |
| 665 | 674 | ||
| 675 | if (priv->soc_info->use_extended_hwdesc) { | ||
| 676 | hwdesc->cmd |= JZ_LCD_CMD_FRM_ENABLE; | ||
| 677 | |||
| 678 | /* Extended 8-byte descriptor */ | ||
| 679 | hwdesc->cpos = 0; | ||
| 680 | hwdesc->offsize = 0; | ||
| 681 | hwdesc->pagewidth = 0; | ||
| 682 | |||
| 683 | switch (newstate->fb->format->format) { | ||
| 684 | case DRM_FORMAT_XRGB1555: | ||
| 685 | hwdesc->cpos |= JZ_LCD_CPOS_RGB555; | ||
| 686 | fallthrough; | ||
| 687 | case DRM_FORMAT_RGB565: | ||
| 688 | hwdesc->cpos |= JZ_LCD_CPOS_BPP_15_16; | ||
| 689 | break; | ||
| 690 | case DRM_FORMAT_XRGB8888: | ||
| 691 | hwdesc->cpos |= JZ_LCD_CPOS_BPP_18_24; | ||
| 692 | break; | ||
| 693 | } | ||
| 694 | hwdesc->cpos |= (JZ_LCD_CPOS_COEFFICIENT_1 << | ||
| 695 | JZ_LCD_CPOS_COEFFICIENT_OFFSET); | ||
| 696 | hwdesc->dessize = | ||
| 697 | (0xff << JZ_LCD_DESSIZE_ALPHA_OFFSET) | | ||
| 698 | FIELD_PREP(JZ_LCD_DESSIZE_HEIGHT_MASK, height - 1) | | ||
| 699 | FIELD_PREP(JZ_LCD_DESSIZE_WIDTH_MASK, width - 1); | ||
| 700 | } | ||
| 701 | |||
| 666 | if (drm_atomic_crtc_needs_modeset(crtc_state)) { | 702 | if (drm_atomic_crtc_needs_modeset(crtc_state)) { |
| 667 | fourcc = newstate->fb->format->format; | 703 | fourcc = newstate->fb->format->format; |
| 668 | 704 | ||
| @@ -694,6 +730,9 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder, · 25 unmodified lines | |||
| 694 | | JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE; | 730 | | JZ_LCD_CFG_SPL_DISABLE | JZ_LCD_CFG_REV_DISABLE; |
| 695 | } | 731 | } |
| 696 | 732 | ||
| 733 | if (priv->soc_info->use_extended_hwdesc) | ||
| 734 | cfg |= JZ_LCD_CFG_DESCRIPTOR_8; | ||
| 735 | |||
| 697 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | 736 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) |
| 698 | cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; | 737 | cfg |= JZ_LCD_CFG_HSYNC_ACTIVE_LOW; |
| 699 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | 738 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) |
| @@ -1011,6 +1050,8 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) · 311 unmodified lines | |||
| 1011 | struct ingenic_drm_bridge *ib; | 1050 | struct ingenic_drm_bridge *ib; |
| 1012 | struct drm_device *drm; | 1051 | struct drm_device *drm; |
| 1013 | void __iomem *base; | 1052 | void __iomem *base; |
| 1053 | struct resource *res; | ||
| 1054 | struct regmap_config regmap_config; | ||
| 1014 | long parent_rate; | 1055 | long parent_rate; |
| 1015 | unsigned int i, clone_mask = 0; | 1056 | unsigned int i, clone_mask = 0; |
| 1016 | int ret, irq; | 1057 | int ret, irq; |
| @@ -1056,14 +1097,16 @@ static int ingenic_drm_bind(struct device *dev, bool has_components) · 39 unmodified lines | |||
| 1056 | drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; | 1097 | drm->mode_config.funcs = &ingenic_drm_mode_config_funcs; |
| 1057 | drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; | 1098 | drm->mode_config.helper_private = &ingenic_drm_mode_config_helpers; |
| 1058 | 1099 | ||
| 1059 | base = devm_platform_ioremap_resource(pdev, 0); | 1100 | base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); |
| 1060 | if (IS_ERR(base)) { | 1101 | if (IS_ERR(base)) { |
| 1061 | dev_err(dev, "Failed to get memory resource\n"); | 1102 | dev_err(dev, "Failed to get memory resource\n"); |
| 1062 | return PTR_ERR(base); | 1103 | return PTR_ERR(base); |
| 1063 | } | 1104 | } |
| 1064 | 1105 | ||
| 1106 | regmap_config = ingenic_drm_regmap_config; | ||
| 1107 | regmap_config.max_register = res->end - res->start; | ||
| 1065 | priv->map = devm_regmap_init_mmio(dev, base, | 1108 | priv->map = devm_regmap_init_mmio(dev, base, |
| 1066 | &ingenic_drm_regmap_config); | 1109 | ®map_config); |
| 1067 | if (IS_ERR(priv->map)) { | 1110 | if (IS_ERR(priv->map)) { |
| 1068 | dev_err(dev, "Failed to create regmap\n"); | 1111 | dev_err(dev, "Failed to create regmap\n"); |
| 1069 | return PTR_ERR(priv->map); | 1112 | return PTR_ERR(priv->map); |
| @@ -1465,10 +1508,23 @@ static const struct jz_soc_info jz4770_soc_info = { · 395 unmodified lines | |||
| 1465 | .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), | 1508 | .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), |
| 1466 | }; | 1509 | }; |
| 1467 | 1510 | ||
| 1511 | static const struct jz_soc_info jz4780_soc_info = { | ||
| 1512 | .needs_dev_clk = true, | ||
| 1513 | .has_osd = true, | ||
| 1514 | .use_extended_hwdesc = true, | ||
| 1515 | .max_width = 4096, | ||
| 1516 | .max_height = 2048, | ||
| 1517 | .formats_f1 = jz4770_formats_f1, | ||
| 1518 | .num_formats_f1 = ARRAY_SIZE(jz4770_formats_f1), | ||
| 1519 | .formats_f0 = jz4770_formats_f0, | ||
| 1520 | .num_formats_f0 = ARRAY_SIZE(jz4770_formats_f0), | ||
| 1521 | }; | ||
| 1522 | |||
| 1468 | static const struct of_device_id ingenic_drm_of_match[] = { | 1523 | static const struct of_device_id ingenic_drm_of_match[] = { |
| 1469 | { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, | 1524 | { .compatible = "ingenic,jz4740-lcd", .data = &jz4740_soc_info }, |
| 1470 | { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, | 1525 | { .compatible = "ingenic,jz4725b-lcd", .data = &jz4725b_soc_info }, |
| 1471 | { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, | 1526 | { .compatible = "ingenic,jz4770-lcd", .data = &jz4770_soc_info }, |
| 1527 | { .compatible = "ingenic,jz4780-lcd", .data = &jz4780_soc_info }, | ||
| 1472 | { /* sentinel */ }, | 1528 | { /* sentinel */ }, |
| 1473 | }; | 1529 | }; |
| 1474 | MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); | 1530 | MODULE_DEVICE_TABLE(of, ingenic_drm_of_match); |
| @@ -44,8 +44,11 @@ · 43 unmodified lines | |||
| 44 | #define JZ_REG_LCD_XYP1 0x124 | 44 | #define JZ_REG_LCD_XYP1 0x124 |
| 45 | #define JZ_REG_LCD_SIZE0 0x128 | 45 | #define JZ_REG_LCD_SIZE0 0x128 |
| 46 | #define JZ_REG_LCD_SIZE1 0x12c | 46 | #define JZ_REG_LCD_SIZE1 0x12c |
| 47 | #define JZ_REG_LCD_PCFG 0x2c0 | ||
| 47 | 48 | ||
| 48 | #define JZ_LCD_CFG_SLCD BIT(31) | 49 | #define JZ_LCD_CFG_SLCD BIT(31) |
| 50 | #define JZ_LCD_CFG_DESCRIPTOR_8 BIT(28) | ||
| 51 | #define JZ_LCD_CFG_RECOVER_FIFO_UNDERRUN BIT(25) | ||
| 49 | #define JZ_LCD_CFG_PS_DISABLE BIT(23) | 52 | #define JZ_LCD_CFG_PS_DISABLE BIT(23) |
| 50 | #define JZ_LCD_CFG_CLS_DISABLE BIT(22) | 53 | #define JZ_LCD_CFG_CLS_DISABLE BIT(22) |
| 51 | #define JZ_LCD_CFG_SPL_DISABLE BIT(21) | 54 | #define JZ_LCD_CFG_SPL_DISABLE BIT(21) |
| @@ -63,6 +66,7 @@ · 11 unmodified lines | |||
| 63 | #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) | 66 | #define JZ_LCD_CFG_DE_ACTIVE_LOW BIT(9) |
| 64 | #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) | 67 | #define JZ_LCD_CFG_VSYNC_ACTIVE_LOW BIT(8) |
| 65 | #define JZ_LCD_CFG_18_BIT BIT(7) | 68 | #define JZ_LCD_CFG_18_BIT BIT(7) |
| 69 | #define JZ_LCD_CFG_24_BIT BIT(6) | ||
| 66 | #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) | 70 | #define JZ_LCD_CFG_PDW (BIT(5) | BIT(4)) |
| 67 | 71 | ||
| 68 | #define JZ_LCD_CFG_MODE_GENERIC_16BIT 0 | 72 | #define JZ_LCD_CFG_MODE_GENERIC_16BIT 0 |
| @@ -132,6 +136,7 @@ · 63 unmodified lines | |||
| 132 | #define JZ_LCD_CMD_SOF_IRQ BIT(31) | 136 | #define JZ_LCD_CMD_SOF_IRQ BIT(31) |
| 133 | #define JZ_LCD_CMD_EOF_IRQ BIT(30) | 137 | #define JZ_LCD_CMD_EOF_IRQ BIT(30) |
| 134 | #define JZ_LCD_CMD_ENABLE_PAL BIT(28) | 138 | #define JZ_LCD_CMD_ENABLE_PAL BIT(28) |
| 139 | #define JZ_LCD_CMD_FRM_ENABLE BIT(26) | ||
| 135 | 140 | ||
| 136 | #define JZ_LCD_SYNC_MASK 0x3ff | 141 | #define JZ_LCD_SYNC_MASK 0x3ff |
| 137 | 142 | ||
| @@ -153,6 +158,7 @@ · 15 unmodified lines | |||
| 153 | #define JZ_LCD_RGBC_EVEN_BGR (0x5 << 0) | 158 | #define JZ_LCD_RGBC_EVEN_BGR (0x5 << 0) |
| 154 | 159 | ||
| 155 | #define JZ_LCD_OSDC_OSDEN BIT(0) | 160 | #define JZ_LCD_OSDC_OSDEN BIT(0) |
| 161 | #define JZ_LCD_OSDC_ALPHAEN BIT(2) | ||
| 156 | #define JZ_LCD_OSDC_F0EN BIT(3) | 162 | #define JZ_LCD_OSDC_F0EN BIT(3) |
| 157 | #define JZ_LCD_OSDC_F1EN BIT(4) | 163 | #define JZ_LCD_OSDC_F1EN BIT(4) |
| 158 | 164 | ||
| @@ -176,6 +182,38 @@ · 17 unmodified lines | |||
| 176 | #define JZ_LCD_SIZE01_WIDTH_LSB 0 | 182 | #define JZ_LCD_SIZE01_WIDTH_LSB 0 |
| 177 | #define JZ_LCD_SIZE01_HEIGHT_LSB 16 | 183 | #define JZ_LCD_SIZE01_HEIGHT_LSB 16 |
| 178 | 184 | ||
| 185 | #define JZ_LCD_DESSIZE_ALPHA_OFFSET 24 | ||
| 186 | #define JZ_LCD_DESSIZE_HEIGHT_MASK GENMASK(23, 12) | ||
| 187 | #define JZ_LCD_DESSIZE_WIDTH_MASK GENMASK(11, 0) | ||
| 188 | |||
| 189 | #define JZ_LCD_CPOS_BPP_15_16 (4 << 27) | ||
| 190 | #define JZ_LCD_CPOS_BPP_18_24 (5 << 27) | ||
| 191 | #define JZ_LCD_CPOS_BPP_30 (7 << 27) | ||
| 192 | #define JZ_LCD_CPOS_RGB555 BIT(30) | ||
| 193 | #define JZ_LCD_CPOS_PREMULTIPLY_LCD BIT(26) | ||
| 194 | #define JZ_LCD_CPOS_COEFFICIENT_OFFSET 24 | ||
| 195 | #define JZ_LCD_CPOS_COEFFICIENT_0 0 | ||
| 196 | #define JZ_LCD_CPOS_COEFFICIENT_1 1 | ||
| 197 | #define JZ_LCD_CPOS_COEFFICIENT_ALPHA1 2 | ||
| 198 | #define JZ_LCD_CPOS_COEFFICIENT_1_ALPHA1 3 | ||
| 199 | |||
| 200 | #define JZ_LCD_RGBC_RGB_PADDING BIT(15) | ||
| 201 | #define JZ_LCD_RGBC_RGB_PADDING_FIRST BIT(14) | ||
| 202 | #define JZ_LCD_RGBC_422 BIT(8) | ||
| 203 | #define JZ_LCD_RGBC_RGB_FORMAT_ENABLE BIT(7) | ||
| 204 | |||
| 205 | #define JZ_LCD_PCFG_PRI_MODE BIT(31) | ||
| 206 | #define JZ_LCD_PCFG_HP_BST_4 (0 << 28) | ||
| 207 | #define JZ_LCD_PCFG_HP_BST_8 (1 << 28) | ||
| 208 | #define JZ_LCD_PCFG_HP_BST_16 (2 << 28) | ||
| 209 | #define JZ_LCD_PCFG_HP_BST_32 (3 << 28) | ||
| 210 | #define JZ_LCD_PCFG_HP_BST_64 (4 << 28) | ||
| 211 | #define JZ_LCD_PCFG_HP_BST_16_CONT (5 << 28) | ||
| 212 | #define JZ_LCD_PCFG_HP_BST_DISABLE (7 << 28) | ||
| 213 | #define JZ_LCD_PCFG_THRESHOLD2_OFFSET 18 | ||
| 214 | #define JZ_LCD_PCFG_THRESHOLD1_OFFSET 9 | ||
| 215 | #define JZ_LCD_PCFG_THRESHOLD0_OFFSET 0 | ||
| 216 | |||
| 179 | struct device; | 217 | struct device; |
| 180 | struct drm_plane; | 218 | struct drm_plane; |
| 181 | struct drm_plane_state; | 219 | struct drm_plane_state; |
| @@ -302,42 +302,42 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) · 301 unmodified lines | |||
| 302 | if (priv->afbcd.ops) { | 302 | if (priv->afbcd.ops) { |
| 303 | ret = priv->afbcd.ops->init(priv); | 303 | ret = priv->afbcd.ops->init(priv); |
| 304 | if (ret) | 304 | if (ret) |
| 305 | return ret; | 305 | goto free_drm; |
| 306 | } | 306 | } |
| 307 | 307 | ||
| 308 | /* Encoder Initialization */ | 308 | /* Encoder Initialization */ |
| 309 | 309 | ||
| 310 | ret = meson_encoder_cvbs_init(priv); | 310 | ret = meson_encoder_cvbs_init(priv); |
| 311 | if (ret) | 311 | if (ret) |
| 312 | goto free_drm; | 312 | goto exit_afbcd; |
| 313 | 313 | ||
| 314 | if (has_components) { | 314 | if (has_components) { |
| 315 | ret = component_bind_all(drm->dev, drm); | 315 | ret = component_bind_all(drm->dev, drm); |
| 316 | if (ret) { | 316 | if (ret) { |
| 317 | dev_err(drm->dev, "Couldn't bind all components\n"); | 317 | dev_err(drm->dev, "Couldn't bind all components\n"); |
| 318 | goto free_drm; | 318 | goto exit_afbcd; |
| 319 | } | 319 | } |
| 320 | } | 320 | } |
| 321 | 321 | ||
| 322 | ret = meson_encoder_hdmi_init(priv); | 322 | ret = meson_encoder_hdmi_init(priv); |
| 323 | if (ret) | 323 | if (ret) |
| 324 | goto free_drm; | 324 | goto exit_afbcd; |
| 325 | 325 | ||
| 326 | ret = meson_plane_create(priv); | 326 | ret = meson_plane_create(priv); |
| 327 | if (ret) | 327 | if (ret) |
| 328 | goto free_drm; | 328 | goto exit_afbcd; |
| 329 | 329 | ||
| 330 | ret = meson_overlay_create(priv); | 330 | ret = meson_overlay_create(priv); |
| 331 | if (ret) | 331 | if (ret) |
| 332 | goto free_drm; | 332 | goto exit_afbcd; |
| 333 | 333 | ||
| 334 | ret = meson_crtc_create(priv); | 334 | ret = meson_crtc_create(priv); |
| 335 | if (ret) | 335 | if (ret) |
| 336 | goto free_drm; | 336 | goto exit_afbcd; |
| 337 | 337 | ||
| 338 | ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); | 338 | ret = request_irq(priv->vsync_irq, meson_irq, 0, drm->driver->name, drm); |
| 339 | if (ret) | 339 | if (ret) |
| 340 | goto free_drm; | 340 | goto exit_afbcd; |
| 341 | 341 | ||
| 342 | drm_mode_config_reset(drm); | 342 | drm_mode_config_reset(drm); |
| 343 | 343 | ||
| @@ -355,6 +355,9 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) · 11 unmodified lines | |||
| 355 | 355 | ||
| 356 | uninstall_irq: | 356 | uninstall_irq: |
| 357 | free_irq(priv->vsync_irq, drm); | 357 | free_irq(priv->vsync_irq, drm); |
| 358 | exit_afbcd: | ||
| 359 | if (priv->afbcd.ops) | ||
| 360 | priv->afbcd.ops->exit(priv); | ||
| 358 | free_drm: | 361 | free_drm: |
| 359 | drm_dev_put(drm); | 362 | drm_dev_put(drm); |
| 360 | 363 | ||
| @@ -385,10 +388,8 @@ static void meson_drv_unbind(struct device *dev) · 24 unmodified lines | |||
| 385 | free_irq(priv->vsync_irq, drm); | 388 | free_irq(priv->vsync_irq, drm); |
| 386 | drm_dev_put(drm); | 389 | drm_dev_put(drm); |
| 387 | 390 | ||
| 388 | if (priv->afbcd.ops) { | 391 | if (priv->afbcd.ops) |
| 389 | priv->afbcd.ops->reset(priv); | 392 | priv->afbcd.ops->exit(priv); |
| 390 | meson_rdma_free(priv); | ||
| 391 | } | ||
| 392 | } | 393 | } |
| 393 | 394 | ||
| 394 | static const struct component_master_ops meson_drv_master_ops = { | 395 | static const struct component_master_ops meson_drv_master_ops = { |
| @@ -79,11 +79,6 @@ static bool meson_gxm_afbcd_supported_fmt(u64 modifier, uint32_t format) · 78 unmodified lines | |||
| 79 | return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; | 79 | return meson_gxm_afbcd_pixel_fmt(modifier, format) >= 0; |
| 80 | } | 80 | } |
| 81 | 81 | ||
| 82 | static int meson_gxm_afbcd_init(struct meson_drm *priv) | ||
| 83 | { | ||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static int meson_gxm_afbcd_reset(struct meson_drm *priv) | 82 | static int meson_gxm_afbcd_reset(struct meson_drm *priv) |
| 88 | { | 83 | { |
| 89 | writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, | 84 | writel_relaxed(VIU_SW_RESET_OSD1_AFBCD, |
| @@ -93,6 +88,16 @@ static int meson_gxm_afbcd_reset(struct meson_drm *priv) · 3 unmodified lines | |||
| 93 | return 0; | 88 | return 0; |
| 94 | } | 89 | } |
| 95 | 90 | ||
| 91 | static int meson_gxm_afbcd_init(struct meson_drm *priv) | ||
| 92 | { | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | |||
| 96 | static void meson_gxm_afbcd_exit(struct meson_drm *priv) | ||
| 97 | { | ||
| 98 | meson_gxm_afbcd_reset(priv); | ||
| 99 | } | ||
| 100 | |||
| 96 | static int meson_gxm_afbcd_enable(struct meson_drm *priv) | 101 | static int meson_gxm_afbcd_enable(struct meson_drm *priv) |
| 97 | { | 102 | { |
| 98 | writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | | 103 | writel_relaxed(FIELD_PREP(OSD1_AFBCD_ID_FIFO_THRD, 0x40) | |
| @@ -172,6 +177,7 @@ static int meson_gxm_afbcd_setup(struct meson_drm *priv) · 73 unmodified lines | |||
| 172 | 177 | ||
| 173 | struct meson_afbcd_ops meson_afbcd_gxm_ops = { | 178 | struct meson_afbcd_ops meson_afbcd_gxm_ops = { |
| 174 | .init = meson_gxm_afbcd_init, | 179 | .init = meson_gxm_afbcd_init, |
| 180 | .exit = meson_gxm_afbcd_exit, | ||
| 175 | .reset = meson_gxm_afbcd_reset, | 181 | .reset = meson_gxm_afbcd_reset, |
| 176 | .enable = meson_gxm_afbcd_enable, | 182 | .enable = meson_gxm_afbcd_enable, |
| 177 | .disable = meson_gxm_afbcd_disable, | 183 | .disable = meson_gxm_afbcd_disable, |
| @@ -269,6 +275,18 @@ static bool meson_g12a_afbcd_supported_fmt(u64 modifier, uint32_t format) · 91 unmodified lines | |||
| 269 | return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; | 275 | return meson_g12a_afbcd_pixel_fmt(modifier, format) >= 0; |
| 270 | } | 276 | } |
| 271 | 277 | ||
| 278 | static int meson_g12a_afbcd_reset(struct meson_drm *priv) | ||
| 279 | { | ||
| 280 | meson_rdma_reset(priv); | ||
| 281 | |||
| 282 | meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | | ||
| 283 | VIU_SW_RESET_G12A_OSD1_AFBCD, | ||
| 284 | VIU_SW_RESET); | ||
| 285 | meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 272 | static int meson_g12a_afbcd_init(struct meson_drm *priv) | 290 | static int meson_g12a_afbcd_init(struct meson_drm *priv) |
| 273 | { | 291 | { |
| 274 | int ret; | 292 | int ret; |
| @@ -286,16 +304,10 @@ static int meson_g12a_afbcd_init(struct meson_drm *priv) · 11 unmodified lines | |||
| 286 | return 0; | 304 | return 0; |
| 287 | } | 305 | } |
| 288 | 306 | ||
| 289 | static int meson_g12a_afbcd_reset(struct meson_drm *priv) | 307 | static void meson_g12a_afbcd_exit(struct meson_drm *priv) |
| 290 | { | 308 | { |
| 291 | meson_rdma_reset(priv); | 309 | meson_g12a_afbcd_reset(priv); |
| 292 | 310 | meson_rdma_free(priv); | |
| 293 | meson_rdma_writel_sync(priv, VIU_SW_RESET_G12A_AFBC_ARB | | ||
| 294 | VIU_SW_RESET_G12A_OSD1_AFBCD, | ||
| 295 | VIU_SW_RESET); | ||
| 296 | meson_rdma_writel_sync(priv, 0, VIU_SW_RESET); | ||
| 297 | |||
| 298 | return 0; | ||
| 299 | } | 311 | } |
| 300 | 312 | ||
| 301 | static int meson_g12a_afbcd_enable(struct meson_drm *priv) | 313 | static int meson_g12a_afbcd_enable(struct meson_drm *priv) |
| @@ -380,6 +392,7 @@ static int meson_g12a_afbcd_setup(struct meson_drm *priv) · 78 unmodified lines | |||
| 380 | 392 | ||
| 381 | struct meson_afbcd_ops meson_afbcd_g12a_ops = { | 393 | struct meson_afbcd_ops meson_afbcd_g12a_ops = { |
| 382 | .init = meson_g12a_afbcd_init, | 394 | .init = meson_g12a_afbcd_init, |
| 395 | .exit = meson_g12a_afbcd_exit, | ||
| 383 | .reset = meson_g12a_afbcd_reset, | 396 | .reset = meson_g12a_afbcd_reset, |
| 384 | .enable = meson_g12a_afbcd_enable, | 397 | .enable = meson_g12a_afbcd_enable, |
| 385 | .disable = meson_g12a_afbcd_disable, | 398 | .disable = meson_g12a_afbcd_disable, |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | struct meson_afbcd_ops { | 15 | struct meson_afbcd_ops { |
| 16 | int (*init)(struct meson_drm *priv); | 16 | int (*init)(struct meson_drm *priv); |
| 17 | void (*exit)(struct meson_drm *priv); | ||
| 17 | int (*reset)(struct meson_drm *priv); | 18 | int (*reset)(struct meson_drm *priv); |
| 18 | int (*enable)(struct meson_drm *priv); | 19 | int (*enable)(struct meson_drm *priv); |
| 19 | int (*disable)(struct meson_drm *priv); | 20 | int (*disable)(struct meson_drm *priv); |
| @@ -529,7 +529,10 @@ static void mgag200_set_format_regs(struct mga_device *mdev, · 528 unmodified lines | |||
| 529 | WREG_GFX(3, 0x00); | 529 | WREG_GFX(3, 0x00); |
| 530 | WREG_GFX(4, 0x00); | 530 | WREG_GFX(4, 0x00); |
| 531 | WREG_GFX(5, 0x40); | 531 | WREG_GFX(5, 0x40); |
| 532 | WREG_GFX(6, 0x05); | 532 | /* GCTL6 should be 0x05, but we configure memmapsl to 0xb8000 (text mode), |
| 533 | * so that it doesn't hang when running kexec/kdump on G200_SE rev42. | ||
| 534 | */ | ||
| 535 | WREG_GFX(6, 0x0d); | ||
| 533 | WREG_GFX(7, 0x0f); | 536 | WREG_GFX(7, 0x0f); |
| 534 | WREG_GFX(8, 0x0f); | 537 | WREG_GFX(8, 0x0f); |
| 535 | 538 | ||
| @@ -12,6 +12,7 @@ config DRM_MSM · 11 unmodified lines | |||
| 12 | select IOMMU_IO_PGTABLE | 12 | select IOMMU_IO_PGTABLE |
| 13 | select QCOM_MDT_LOADER if ARCH_QCOM | 13 | select QCOM_MDT_LOADER if ARCH_QCOM |
| 14 | select REGULATOR | 14 | select REGULATOR |
| 15 | select DRM_DP_HELPER | ||
| 15 | select DRM_KMS_HELPER | 16 | select DRM_KMS_HELPER |
| 16 | select DRM_PANEL | 17 | select DRM_PANEL |
| 17 | select DRM_BRIDGE | 18 | select DRM_BRIDGE |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/of_platform.h> | 9 | #include <linux/of_platform.h> |
| 10 | 10 | ||
| 11 | #include <drm/drm_dp_helper.h> | 11 | #include <drm/dp/drm_dp_helper.h> |
| 12 | #include <drm/drm_edid.h> | 12 | #include <drm/drm_edid.h> |
| 13 | 13 | ||
| 14 | #include "dp_catalog.h" | 14 | #include "dp_catalog.h" |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | |||
| 7 | #define _DP_AUX_H_ | 7 | #define _DP_AUX_H_ |
| 8 | 8 | ||
| 9 | #include "dp_catalog.h" | 9 | #include "dp_catalog.h" |
| 10 | #include <drm/drm_dp_helper.h> | 10 | #include <drm/dp/drm_dp_helper.h> |
| 11 | 11 | ||
| 12 | int dp_aux_register(struct drm_dp_aux *dp_aux); | 12 | int dp_aux_register(struct drm_dp_aux *dp_aux); |
| 13 | void dp_aux_unregister(struct drm_dp_aux *dp_aux); | 13 | void dp_aux_unregister(struct drm_dp_aux *dp_aux); |
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/phy/phy.h> | 10 | #include <linux/phy/phy.h> |
| 11 | #include <linux/phy/phy-dp.h> | 11 | #include <linux/phy/phy-dp.h> |
| 12 | #include <linux/rational.h> | 12 | #include <linux/rational.h> |
| 13 | #include <drm/drm_dp_helper.h> | 13 | #include <drm/dp/drm_dp_helper.h> |
| 14 | #include <drm/drm_print.h> | 14 | #include <drm/drm_print.h> |
| 15 | 15 | ||
| 16 | #include "dp_catalog.h" | 16 | #include "dp_catalog.h" |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/phy/phy-dp.h> | 12 | #include <linux/phy/phy-dp.h> |
| 13 | #include <linux/pm_opp.h> | 13 | #include <linux/pm_opp.h> |
| 14 | #include <drm/drm_fixed.h> | 14 | #include <drm/drm_fixed.h> |
| 15 | #include <drm/drm_dp_helper.h> | 15 | #include <drm/dp/drm_dp_helper.h> |
| 16 | #include <drm/drm_print.h> | 16 | #include <drm/drm_print.h> |
| 17 | 17 | ||
| 18 | #include "dp_reg.h" | 18 | #include "dp_reg.h" |
| @@ -0,0 +1,77 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef __EDP_CONNECTOR_H__ | ||
| 7 | #define __EDP_CONNECTOR_H__ | ||
| 8 | |||
| 9 | #include <linux/i2c.h> | ||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/platform_device.h> | ||
| 13 | #include <drm/dp/drm_dp_helper.h> | ||
| 14 | #include <drm/drm_bridge.h> | ||
| 15 | #include <drm/drm_crtc.h> | ||
| 16 | |||
| 17 | #include "msm_drv.h" | ||
| 18 | |||
| 19 | #define edp_read(offset) msm_readl((offset)) | ||
| 20 | #define edp_write(offset, data) msm_writel((data), (offset)) | ||
| 21 | |||
| 22 | struct edp_ctrl; | ||
| 23 | struct edp_aux; | ||
| 24 | struct edp_phy; | ||
| 25 | |||
| 26 | struct msm_edp { | ||
| 27 | struct drm_device *dev; | ||
| 28 | struct platform_device *pdev; | ||
| 29 | |||
| 30 | struct drm_connector *connector; | ||
| 31 | struct drm_bridge *bridge; | ||
| 32 | |||
| 33 | /* the encoder we are hooked to (outside of eDP block) */ | ||
| 34 | struct drm_encoder *encoder; | ||
| 35 | |||
| 36 | struct edp_ctrl *ctrl; | ||
| 37 | |||
| 38 | int irq; | ||
| 39 | }; | ||
| 40 | |||
| 41 | /* eDP bridge */ | ||
| 42 | struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp); | ||
| 43 | void edp_bridge_destroy(struct drm_bridge *bridge); | ||
| 44 | |||
| 45 | /* eDP connector */ | ||
| 46 | struct drm_connector *msm_edp_connector_init(struct msm_edp *edp); | ||
| 47 | |||
| 48 | /* AUX */ | ||
| 49 | void *msm_edp_aux_init(struct msm_edp *edp, void __iomem *regbase, struct drm_dp_aux **drm_aux); | ||
| 50 | void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux); | ||
| 51 | irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr); | ||
| 52 | void msm_edp_aux_ctrl(struct edp_aux *aux, int enable); | ||
| 53 | |||
| 54 | /* Phy */ | ||
| 55 | bool msm_edp_phy_ready(struct edp_phy *phy); | ||
| 56 | void msm_edp_phy_ctrl(struct edp_phy *phy, int enable); | ||
| 57 | void msm_edp_phy_vm_pe_init(struct edp_phy *phy); | ||
| 58 | void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1); | ||
| 59 | void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane); | ||
| 60 | void *msm_edp_phy_init(struct device *dev, void __iomem *regbase); | ||
| 61 | |||
| 62 | /* Ctrl */ | ||
| 63 | irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl); | ||
| 64 | void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on); | ||
| 65 | int msm_edp_ctrl_init(struct msm_edp *edp); | ||
| 66 | void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl); | ||
| 67 | bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl); | ||
| 68 | int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, | ||
| 69 | struct drm_connector *connector, struct edid **edid); | ||
| 70 | int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, | ||
| 71 | const struct drm_display_mode *mode, | ||
| 72 | const struct drm_display_info *info); | ||
| 73 | /* @pixel_rate is in kHz */ | ||
| 74 | bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl, | ||
| 75 | u32 pixel_rate, u32 *pm, u32 *pn); | ||
| 76 | |||
| 77 | #endif /* __EDP_CONNECTOR_H__ */ | ||
| @@ -0,0 +1,1373 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* | ||
| 3 | * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/clk.h> | ||
| 7 | #include <linux/gpio/consumer.h> | ||
| 8 | #include <linux/regulator/consumer.h> | ||
| 9 | #include <drm/dp/drm_dp_helper.h> | ||
| 10 | #include <drm/drm_crtc.h> | ||
| 11 | #include <drm/drm_edid.h> | ||
| 12 | |||
| 13 | #include "edp.h" | ||
| 14 | #include "edp.xml.h" | ||
| 15 | |||
| 16 | #define VDDA_UA_ON_LOAD 100000 /* uA units */ | ||
| 17 | #define VDDA_UA_OFF_LOAD 100 /* uA units */ | ||
| 18 | |||
| 19 | #define DPCD_LINK_VOLTAGE_MAX 4 | ||
| 20 | #define DPCD_LINK_PRE_EMPHASIS_MAX 4 | ||
| 21 | |||
| 22 | #define EDP_LINK_BW_MAX DP_LINK_BW_2_7 | ||
| 23 | |||
| 24 | /* Link training return value */ | ||
| 25 | #define EDP_TRAIN_FAIL -1 | ||
| 26 | #define EDP_TRAIN_SUCCESS 0 | ||
| 27 | #define EDP_TRAIN_RECONFIG 1 | ||
| 28 | |||
| 29 | #define EDP_CLK_MASK_AHB BIT(0) | ||
| 30 | #define EDP_CLK_MASK_AUX BIT(1) | ||
| 31 | #define EDP_CLK_MASK_LINK BIT(2) | ||
| 32 | #define EDP_CLK_MASK_PIXEL BIT(3) | ||
| 33 | #define EDP_CLK_MASK_MDP_CORE BIT(4) | ||
| 34 | #define EDP_CLK_MASK_LINK_CHAN (EDP_CLK_MASK_LINK | EDP_CLK_MASK_PIXEL) | ||
| 35 | #define EDP_CLK_MASK_AUX_CHAN \ | ||
| 36 | (EDP_CLK_MASK_AHB | EDP_CLK_MASK_AUX | EDP_CLK_MASK_MDP_CORE) | ||
| 37 | #define EDP_CLK_MASK_ALL (EDP_CLK_MASK_AUX_CHAN | EDP_CLK_MASK_LINK_CHAN) | ||
| 38 | |||
| 39 | #define EDP_BACKLIGHT_MAX 255 | ||
| 40 | |||
| 41 | #define EDP_INTR_STATUS1 \ | ||
| 42 | (EDP_INTERRUPT_REG_1_HPD | EDP_INTERRUPT_REG_1_AUX_I2C_DONE | \ | ||
| 43 | EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \ | ||
| 44 | EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \ | ||
| 45 | EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER | \ | ||
| 46 | EDP_INTERRUPT_REG_1_PLL_UNLOCK | EDP_INTERRUPT_REG_1_AUX_ERROR) | ||
| 47 | #define EDP_INTR_MASK1 (EDP_INTR_STATUS1 << 2) | ||
| 48 | #define EDP_INTR_STATUS2 \ | ||
| 49 | (EDP_INTERRUPT_REG_2_READY_FOR_VIDEO | \ | ||
| 50 | EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT | \ | ||
| 51 | EDP_INTERRUPT_REG_2_FRAME_END | EDP_INTERRUPT_REG_2_CRC_UPDATED) | ||
| 52 | #define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2) | ||
| 53 | |||
| 54 | struct edp_ctrl { | ||
| 55 | struct platform_device *pdev; | ||
| 56 | |||
| 57 | void __iomem *base; | ||
| 58 | |||
| 59 | /* regulators */ | ||
| 60 | struct regulator *vdda_vreg; /* 1.8 V */ | ||
| 61 | struct regulator *lvl_vreg; | ||
| 62 | |||
| 63 | /* clocks */ | ||
| 64 | struct clk *aux_clk; | ||
| 65 | struct clk *pixel_clk; | ||
| 66 | struct clk *ahb_clk; | ||
| 67 | struct clk *link_clk; | ||
| 68 | struct clk *mdp_core_clk; | ||
| 69 | |||
| 70 | /* gpios */ | ||
| 71 | struct gpio_desc *panel_en_gpio; | ||
| 72 | struct gpio_desc *panel_hpd_gpio; | ||
| 73 | |||
| 74 | /* completion and mutex */ | ||
| 75 | struct completion idle_comp; | ||
| 76 | struct mutex dev_mutex; /* To protect device power status */ | ||
| 77 | |||
| 78 | /* work queue */ | ||
| 79 | struct work_struct on_work; | ||
| 80 | struct work_struct off_work; | ||
| 81 | struct workqueue_struct *workqueue; | ||
| 82 | |||
| 83 | /* Interrupt register lock */ | ||
| 84 | spinlock_t irq_lock; | ||
| 85 | |||
| 86 | bool edp_connected; | ||
| 87 | bool power_on; | ||
| 88 | |||
| 89 | /* edid raw data */ | ||
| 90 | struct edid *edid; | ||
| 91 | |||
| 92 | struct drm_dp_aux *drm_aux; | ||
| 93 | |||
| 94 | /* dpcd raw data */ | ||
| 95 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; | ||
| 96 | |||
| 97 | /* Link status */ | ||
| 98 | u8 link_rate; | ||
| 99 | u8 lane_cnt; | ||
| 100 | u8 v_level; | ||
| 101 | u8 p_level; | ||
| 102 | |||
| 103 | /* Timing status */ | ||
| 104 | u8 interlaced; | ||
| 105 | u32 pixel_rate; /* in kHz */ | ||
| 106 | u32 color_depth; | ||
| 107 | |||
| 108 | struct edp_aux *aux; | ||
| 109 | struct edp_phy *phy; | ||
| 110 | }; | ||
| 111 | |||
| 112 | struct edp_pixel_clk_div { | ||
| 113 | u32 rate; /* in kHz */ | ||
| 114 | u32 m; | ||
| 115 | u32 n; | ||
| 116 | }; | ||
| 117 | |||
| 118 | #define EDP_PIXEL_CLK_NUM 8 | ||
| 119 | static const struct edp_pixel_clk_div clk_divs[2][EDP_PIXEL_CLK_NUM] = { | ||
| 120 | { /* Link clock = 162MHz, source clock = 810MHz */ | ||
| 121 | {119000, 31, 211}, /* WSXGA+ 1680x1050@60Hz CVT */ | ||
| 122 | {130250, 32, 199}, /* UXGA 1600x1200@60Hz CVT */ | ||
| 123 | {148500, 11, 60}, /* FHD 1920x1080@60Hz */ | ||
| 124 | {154000, 50, 263}, /* WUXGA 1920x1200@60Hz CVT */ | ||
| 125 | {209250, 31, 120}, /* QXGA 2048x1536@60Hz CVT */ | ||
| 126 | {268500, 119, 359}, /* WQXGA 2560x1600@60Hz CVT */ | ||
| 127 | {138530, 33, 193}, /* AUO B116HAN03.0 Panel */ | ||
| 128 | {141400, 48, 275}, /* AUO B133HTN01.2 Panel */ | ||
| 129 | }, | ||
| 130 | { /* Link clock = 270MHz, source clock = 675MHz */ | ||
| 131 | {119000, 52, 295}, /* WSXGA+ 1680x1050@60Hz CVT */ | ||
| 132 | {130250, 11, 57}, /* UXGA 1600x1200@60Hz CVT */ | ||
| 133 | {148500, 11, 50}, /* FHD 1920x1080@60Hz */ | ||
| 134 | {154000, 47, 206}, /* WUXGA 1920x1200@60Hz CVT */ | ||
| 135 | {209250, 31, 100}, /* QXGA 2048x1536@60Hz CVT */ | ||
| 136 | {268500, 107, 269}, /* WQXGA 2560x1600@60Hz CVT */ | ||
| 137 | {138530, 63, 307}, /* AUO B116HAN03.0 Panel */ | ||
| 138 | {141400, 53, 253}, /* AUO B133HTN01.2 Panel */ | ||
| 139 | }, | ||
| 140 | }; | ||
| 141 | |||
| 142 | static int edp_clk_init(struct edp_ctrl *ctrl) | ||
| 143 | { | ||
| 144 | struct platform_device *pdev = ctrl->pdev; | ||
| 145 | int ret; | ||
| 146 | |||
| 147 | ctrl->aux_clk = msm_clk_get(pdev, "core"); | ||
| 148 | if (IS_ERR(ctrl->aux_clk)) { | ||
| 149 | ret = PTR_ERR(ctrl->aux_clk); | ||
| 150 | pr_err("%s: Can't find core clock, %d\n", __func__, ret); | ||
| 151 | ctrl->aux_clk = NULL; | ||
| 152 | return ret; | ||
| 153 | } | ||
| 154 | |||
| 155 | ctrl->pixel_clk = msm_clk_get(pdev, "pixel"); | ||
| 156 | if (IS_ERR(ctrl->pixel_clk)) { | ||
| 157 | ret = PTR_ERR(ctrl->pixel_clk); | ||
| 158 | pr_err("%s: Can't find pixel clock, %d\n", __func__, ret); | ||
| 159 | ctrl->pixel_clk = NULL; | ||
| 160 | return ret; | ||
| 161 | } | ||
| 162 | |||
| 163 | ctrl->ahb_clk = msm_clk_get(pdev, "iface"); | ||
| 164 | if (IS_ERR(ctrl->ahb_clk)) { | ||
| 165 | ret = PTR_ERR(ctrl->ahb_clk); | ||
| 166 | pr_err("%s: Can't find iface clock, %d\n", __func__, ret); | ||
| 167 | ctrl->ahb_clk = NULL; | ||
| 168 | return ret; | ||
| 169 | } | ||
| 170 | |||
| 171 | ctrl->link_clk = msm_clk_get(pdev, "link"); | ||
| 172 | if (IS_ERR(ctrl->link_clk)) { | ||
| 173 | ret = PTR_ERR(ctrl->link_clk); | ||
| 174 | pr_err("%s: Can't find link clock, %d\n", __func__, ret); | ||
| 175 | ctrl->link_clk = NULL; | ||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 179 | /* need mdp core clock to receive irq */ | ||
| 180 | ctrl->mdp_core_clk = msm_clk_get(pdev, "mdp_core"); | ||
| 181 | if (IS_ERR(ctrl->mdp_core_clk)) { | ||
| 182 | ret = PTR_ERR(ctrl->mdp_core_clk); | ||
| 183 | pr_err("%s: Can't find mdp_core clock, %d\n", __func__, ret); | ||
| 184 | ctrl->mdp_core_clk = NULL; | ||
| 185 | return ret; | ||
| 186 | } | ||
| 187 | |||
| 188 | return 0; | ||
| 189 | } | ||
| 190 | |||
| 191 | static int edp_clk_enable(struct edp_ctrl *ctrl, u32 clk_mask) | ||
| 192 | { | ||
| 193 | int ret; | ||
| 194 | |||
| 195 | DBG("mask=%x", clk_mask); | ||
| 196 | /* ahb_clk should be enabled first */ | ||
| 197 | if (clk_mask & EDP_CLK_MASK_AHB) { | ||
| 198 | ret = clk_prepare_enable(ctrl->ahb_clk); | ||
| 199 | if (ret) { | ||
| 200 | pr_err("%s: Failed to enable ahb clk\n", __func__); | ||
| 201 | goto f0; | ||
| 202 | } | ||
| 203 | } | ||
| 204 | if (clk_mask & EDP_CLK_MASK_AUX) { | ||
| 205 | ret = clk_set_rate(ctrl->aux_clk, 19200000); | ||
| 206 | if (ret) { | ||
| 207 | pr_err("%s: Failed to set rate aux clk\n", __func__); | ||
| 208 | goto f1; | ||
| 209 | } | ||
| 210 | ret = clk_prepare_enable(ctrl->aux_clk); | ||
| 211 | if (ret) { | ||
| 212 | pr_err("%s: Failed to enable aux clk\n", __func__); | ||
| 213 | goto f1; | ||
| 214 | } | ||
| 215 | } | ||
| 216 | /* Need to set rate and enable link_clk prior to pixel_clk */ | ||
| 217 | if (clk_mask & EDP_CLK_MASK_LINK) { | ||
| 218 | DBG("edp->link_clk, set_rate %ld", | ||
| 219 | (unsigned long)ctrl->link_rate * 27000000); | ||
| 220 | ret = clk_set_rate(ctrl->link_clk, | ||
| 221 | (unsigned long)ctrl->link_rate * 27000000); | ||
| 222 | if (ret) { | ||
| 223 | pr_err("%s: Failed to set rate to link clk\n", | ||
| 224 | __func__); | ||
| 225 | goto f2; | ||
| 226 | } | ||
| 227 | |||
| 228 | ret = clk_prepare_enable(ctrl->link_clk); | ||
| 229 | if (ret) { | ||
| 230 | pr_err("%s: Failed to enable link clk\n", __func__); | ||
| 231 | goto f2; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | if (clk_mask & EDP_CLK_MASK_PIXEL) { | ||
| 235 | DBG("edp->pixel_clk, set_rate %ld", | ||
| 236 | (unsigned long)ctrl->pixel_rate * 1000); | ||
| 237 | ret = clk_set_rate(ctrl->pixel_clk, | ||
| 238 | (unsigned long)ctrl->pixel_rate * 1000); | ||
| 239 | if (ret) { | ||
| 240 | pr_err("%s: Failed to set rate to pixel clk\n", | ||
| 241 | __func__); | ||
| 242 | goto f3; | ||
| 243 | } | ||
| 244 | |||
| 245 | ret = clk_prepare_enable(ctrl->pixel_clk); | ||
| 246 | if (ret) { | ||
| 247 | pr_err("%s: Failed to enable pixel clk\n", __func__); | ||
| 248 | goto f3; | ||
| 249 | } | ||
| 250 | } | ||
| 251 | if (clk_mask & EDP_CLK_MASK_MDP_CORE) { | ||
| 252 | ret = clk_prepare_enable(ctrl->mdp_core_clk); | ||
| 253 | if (ret) { | ||
| 254 | pr_err("%s: Failed to enable mdp core clk\n", __func__); | ||
| 255 | goto f4; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | |||
| 261 | f4: | ||
| 262 | if (clk_mask & EDP_CLK_MASK_PIXEL) | ||
| 263 | clk_disable_unprepare(ctrl->pixel_clk); | ||
| 264 | f3: | ||
| 265 | if (clk_mask & EDP_CLK_MASK_LINK) | ||
| 266 | clk_disable_unprepare(ctrl->link_clk); | ||
| 267 | f2: | ||
| 268 | if (clk_mask & EDP_CLK_MASK_AUX) | ||
| 269 | clk_disable_unprepare(ctrl->aux_clk); | ||
| 270 | f1: | ||
| 271 | if (clk_mask & EDP_CLK_MASK_AHB) | ||
| 272 | clk_disable_unprepare(ctrl->ahb_clk); | ||
| 273 | f0: | ||
| 274 | return ret; | ||
| 275 | } | ||
| 276 | |||
| 277 | static void edp_clk_disable(struct edp_ctrl *ctrl, u32 clk_mask) | ||
| 278 | { | ||
| 279 | if (clk_mask & EDP_CLK_MASK_MDP_CORE) | ||
| 280 | clk_disable_unprepare(ctrl->mdp_core_clk); | ||
| 281 | if (clk_mask & EDP_CLK_MASK_PIXEL) | ||
| 282 | clk_disable_unprepare(ctrl->pixel_clk); | ||
| 283 | if (clk_mask & EDP_CLK_MASK_LINK) | ||
| 284 | clk_disable_unprepare(ctrl->link_clk); | ||
| 285 | if (clk_mask & EDP_CLK_MASK_AUX) | ||
| 286 | clk_disable_unprepare(ctrl->aux_clk); | ||
| 287 | if (clk_mask & EDP_CLK_MASK_AHB) | ||
| 288 | clk_disable_unprepare(ctrl->ahb_clk); | ||
| 289 | } | ||
| 290 | |||
| 291 | static int edp_regulator_init(struct edp_ctrl *ctrl) | ||
| 292 | { | ||
| 293 | struct device *dev = &ctrl->pdev->dev; | ||
| 294 | int ret; | ||
| 295 | |||
| 296 | DBG(""); | ||
| 297 | ctrl->vdda_vreg = devm_regulator_get(dev, "vdda"); | ||
| 298 | ret = PTR_ERR_OR_ZERO(ctrl->vdda_vreg); | ||
| 299 | if (ret) { | ||
| 300 | pr_err("%s: Could not get vdda reg, ret = %d\n", __func__, | ||
| 301 | ret); | ||
| 302 | ctrl->vdda_vreg = NULL; | ||
| 303 | return ret; | ||
| 304 | } | ||
| 305 | ctrl->lvl_vreg = devm_regulator_get(dev, "lvl-vdd"); | ||
| 306 | ret = PTR_ERR_OR_ZERO(ctrl->lvl_vreg); | ||
| 307 | if (ret) { | ||
| 308 | pr_err("%s: Could not get lvl-vdd reg, ret = %d\n", __func__, | ||
| 309 | ret); | ||
| 310 | ctrl->lvl_vreg = NULL; | ||
| 311 | return ret; | ||
| 312 | } | ||
| 313 | |||
| 314 | return 0; | ||
| 315 | } | ||
| 316 | |||
| 317 | static int edp_regulator_enable(struct edp_ctrl *ctrl) | ||
| 318 | { | ||
| 319 | int ret; | ||
| 320 | |||
| 321 | ret = regulator_set_load(ctrl->vdda_vreg, VDDA_UA_ON_LOAD); | ||
| 322 | if (ret < 0) { | ||
| 323 | pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__); | ||
| 324 | goto vdda_set_fail; | ||
| 325 | } | ||
| 326 | |||
| 327 | ret = regulator_enable(ctrl->vdda_vreg); | ||
| 328 | if (ret) { | ||
| 329 | pr_err("%s: Failed to enable vdda_vreg regulator.\n", __func__); | ||
| 330 | goto vdda_enable_fail; | ||
| 331 | } | ||
| 332 | |||
| 333 | ret = regulator_enable(ctrl->lvl_vreg); | ||
| 334 | if (ret) { | ||
| 335 | pr_err("Failed to enable lvl-vdd reg regulator, %d", ret); | ||
| 336 | goto lvl_enable_fail; | ||
| 337 | } | ||
| 338 | |||
| 339 | DBG("exit"); | ||
| 340 | return 0; | ||
| 341 | |||
| 342 | lvl_enable_fail: | ||
| 343 | regulator_disable(ctrl->vdda_vreg); | ||
| 344 | vdda_enable_fail: | ||
| 345 | regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); | ||
| 346 | vdda_set_fail: | ||
| 347 | return ret; | ||
| 348 | } | ||
| 349 | |||
| 350 | static void edp_regulator_disable(struct edp_ctrl *ctrl) | ||
| 351 | { | ||
| 352 | regulator_disable(ctrl->lvl_vreg); | ||
| 353 | regulator_disable(ctrl->vdda_vreg); | ||
| 354 | regulator_set_load(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD); | ||
| 355 | } | ||
| 356 | |||
| 357 | static int edp_gpio_config(struct edp_ctrl *ctrl) | ||
| 358 | { | ||
| 359 | struct device *dev = &ctrl->pdev->dev; | ||
| 360 | int ret; | ||
| 361 | |||
| 362 | ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN); | ||
| 363 | if (IS_ERR(ctrl->panel_hpd_gpio)) { | ||
| 364 | ret = PTR_ERR(ctrl->panel_hpd_gpio); | ||
| 365 | ctrl->panel_hpd_gpio = NULL; | ||
| 366 | pr_err("%s: cannot get panel-hpd-gpios, %d\n", __func__, ret); | ||
| 367 | return ret; | ||
| 368 | } | ||
| 369 | |||
| 370 | ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW); | ||
| 371 | if (IS_ERR(ctrl->panel_en_gpio)) { | ||
| 372 | ret = PTR_ERR(ctrl->panel_en_gpio); | ||
| 373 | ctrl->panel_en_gpio = NULL; | ||
| 374 | pr_err("%s: cannot get panel-en-gpios, %d\n", __func__, ret); | ||
| 375 | return ret; | ||
| 376 | } | ||
| 377 | |||
| 378 | DBG("gpio on"); | ||
| 379 | |||
| 380 | return 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | static void edp_ctrl_irq_enable(struct edp_ctrl *ctrl, int enable) | ||
| 384 | { | ||
| 385 | unsigned long flags; | ||
| 386 | |||
| 387 | DBG("%d", enable); | ||
| 388 | spin_lock_irqsave(&ctrl->irq_lock, flags); | ||
| 389 | if (enable) { | ||
| 390 | edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, EDP_INTR_MASK1); | ||
| 391 | edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, EDP_INTR_MASK2); | ||
| 392 | } else { | ||
| 393 | edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, 0x0); | ||
| 394 | edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, 0x0); | ||
| 395 | } | ||
| 396 | spin_unlock_irqrestore(&ctrl->irq_lock, flags); | ||
| 397 | DBG("exit"); | ||
| 398 | } | ||
| 399 | |||
| 400 | static void edp_fill_link_cfg(struct edp_ctrl *ctrl) | ||
| 401 | { | ||
| 402 | u32 prate; | ||
| 403 | u32 lrate; | ||
| 404 | u32 bpp; | ||
| 405 | u8 max_lane = drm_dp_max_lane_count(ctrl->dpcd); | ||
| 406 | u8 lane; | ||
| 407 | |||
| 408 | prate = ctrl->pixel_rate; | ||
| 409 | bpp = ctrl->color_depth * 3; | ||
| 410 | |||
| 411 | /* | ||
| 412 | * By default, use the maximum link rate and minimum lane count, | ||
| 413 | * so that we can do rate down shift during link training. | ||
| 414 | */ | ||
| 415 | ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; | ||
| 416 | |||
| 417 | prate *= bpp; | ||
| 418 | prate /= 8; /* in kByte */ | ||
| 419 | |||
| 420 | lrate = 270000; /* in kHz */ | ||
| 421 | lrate *= ctrl->link_rate; | ||
| 422 | lrate /= 10; /* in kByte, 10 bits --> 8 bits */ | ||
| 423 | |||
| 424 | for (lane = 1; lane <= max_lane; lane <<= 1) { | ||
| 425 | if (lrate >= prate) | ||
| 426 | break; | ||
| 427 | lrate <<= 1; | ||
| 428 | } | ||
| 429 | |||
| 430 | ctrl->lane_cnt = lane; | ||
| 431 | DBG("rate=%d lane=%d", ctrl->link_rate, ctrl->lane_cnt); | ||
| 432 | } | ||
| 433 | |||
| 434 | static void edp_config_ctrl(struct edp_ctrl *ctrl) | ||
| 435 | { | ||
| 436 | u32 data; | ||
| 437 | enum edp_color_depth depth; | ||
| 438 | |||
| 439 | data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1); | ||
| 440 | |||
| 441 | if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) | ||
| 442 | data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING; | ||
| 443 | |||
| 444 | depth = EDP_6BIT; | ||
| 445 | if (ctrl->color_depth == 8) | ||
| 446 | depth = EDP_8BIT; | ||
| 447 | |||
| 448 | data |= EDP_CONFIGURATION_CTRL_COLOR(depth); | ||
| 449 | |||
| 450 | if (!ctrl->interlaced) /* progressive */ | ||
| 451 | data |= EDP_CONFIGURATION_CTRL_PROGRESSIVE; | ||
| 452 | |||
| 453 | data |= (EDP_CONFIGURATION_CTRL_SYNC_CLK | | ||
| 454 | EDP_CONFIGURATION_CTRL_STATIC_MVID); | ||
| 455 | |||
| 456 | edp_write(ctrl->base + REG_EDP_CONFIGURATION_CTRL, data); | ||
| 457 | } | ||
| 458 | |||
| 459 | static void edp_state_ctrl(struct edp_ctrl *ctrl, u32 state) | ||
| 460 | { | ||
| 461 | edp_write(ctrl->base + REG_EDP_STATE_CTRL, state); | ||
| 462 | /* Make sure H/W status is set */ | ||
| 463 | wmb(); | ||
| 464 | } | ||
| 465 | |||
| 466 | static int edp_lane_set_write(struct edp_ctrl *ctrl, | ||
| 467 | u8 voltage_level, u8 pre_emphasis_level) | ||
| 468 | { | ||
| 469 | int i; | ||
| 470 | u8 buf[4]; | ||
| 471 | |||
| 472 | if (voltage_level >= DPCD_LINK_VOLTAGE_MAX) | ||
| 473 | voltage_level |= 0x04; | ||
| 474 | |||
| 475 | if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX) | ||
| 476 | pre_emphasis_level |= 0x04; | ||
| 477 | |||
| 478 | pre_emphasis_level <<= 3; | ||
| 479 | |||
| 480 | for (i = 0; i < 4; i++) | ||
| 481 | buf[i] = voltage_level | pre_emphasis_level; | ||
| 482 | |||
| 483 | DBG("%s: p|v=0x%x", __func__, voltage_level | pre_emphasis_level); | ||
| 484 | if (drm_dp_dpcd_write(ctrl->drm_aux, 0x103, buf, 4) < 4) { | ||
| 485 | pr_err("%s: Set sw/pe to panel failed\n", __func__); | ||
| 486 | return -ENOLINK; | ||
| 487 | } | ||
| 488 | |||
| 489 | return 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | static int edp_train_pattern_set_write(struct edp_ctrl *ctrl, u8 pattern) | ||
| 493 | { | ||
| 494 | u8 p = pattern; | ||
| 495 | |||
| 496 | DBG("pattern=%x", p); | ||
| 497 | if (drm_dp_dpcd_write(ctrl->drm_aux, | ||
| 498 | DP_TRAINING_PATTERN_SET, &p, 1) < 1) { | ||
| 499 | pr_err("%s: Set training pattern to panel failed\n", __func__); | ||
| 500 | return -ENOLINK; | ||
| 501 | } | ||
| 502 | |||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | static void edp_sink_train_set_adjust(struct edp_ctrl *ctrl, | ||
| 507 | const u8 *link_status) | ||
| 508 | { | ||
| 509 | int i; | ||
| 510 | u8 max = 0; | ||
| 511 | u8 data; | ||
| 512 | |||
| 513 | /* use the max level across lanes */ | ||
| 514 | for (i = 0; i < ctrl->lane_cnt; i++) { | ||
| 515 | data = drm_dp_get_adjust_request_voltage(link_status, i); | ||
| 516 | DBG("lane=%d req_voltage_swing=0x%x", i, data); | ||
| 517 | if (max < data) | ||
| 518 | max = data; | ||
| 519 | } | ||
| 520 | |||
| 521 | ctrl->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; | ||
| 522 | |||
| 523 | /* use the max level across lanes */ | ||
| 524 | max = 0; | ||
| 525 | for (i = 0; i < ctrl->lane_cnt; i++) { | ||
| 526 | data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); | ||
| 527 | DBG("lane=%d req_pre_emphasis=0x%x", i, data); | ||
| 528 | if (max < data) | ||
| 529 | max = data; | ||
| 530 | } | ||
| 531 | |||
| 532 | ctrl->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; | ||
| 533 | DBG("v_level=%d, p_level=%d", ctrl->v_level, ctrl->p_level); | ||
| 534 | } | ||
| 535 | |||
| 536 | static void edp_host_train_set(struct edp_ctrl *ctrl, u32 train) | ||
| 537 | { | ||
| 538 | int cnt = 10; | ||
| 539 | u32 data; | ||
| 540 | u32 shift = train - 1; | ||
| 541 | |||
| 542 | DBG("train=%d", train); | ||
| 543 | |||
| 544 | edp_state_ctrl(ctrl, EDP_STATE_CTRL_TRAIN_PATTERN_1 << shift); | ||
| 545 | while (--cnt) { | ||
| 546 | data = edp_read(ctrl->base + REG_EDP_MAINLINK_READY); | ||
| 547 | if (data & (EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY << shift)) | ||
| 548 | break; | ||
| 549 | } | ||
| 550 | |||
| 551 | if (cnt == 0) | ||
| 552 | pr_err("%s: set link_train=%d failed\n", __func__, train); | ||
| 553 | } | ||
| 554 | |||
| 555 | static const u8 vm_pre_emphasis[4][4] = { | ||
| 556 | {0x03, 0x06, 0x09, 0x0C}, /* pe0, 0 db */ | ||
| 557 | {0x03, 0x06, 0x09, 0xFF}, /* pe1, 3.5 db */ | ||
| 558 | {0x03, 0x06, 0xFF, 0xFF}, /* pe2, 6.0 db */ | ||
| 559 | {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ | ||
| 560 | }; | ||
| 561 | |||
| 562 | /* voltage swing, 0.2v and 1.0v are not support */ | ||
| 563 | static const u8 vm_voltage_swing[4][4] = { | ||
| 564 | {0x14, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v */ | ||
| 565 | {0x18, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */ | ||
| 566 | {0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */ | ||
| 567 | {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ | ||
| 568 | }; | ||
| 569 | |||
| 570 | static int edp_voltage_pre_emphasise_set(struct edp_ctrl *ctrl) | ||
| 571 | { | ||
| 572 | u32 value0; | ||
| 573 | u32 value1; | ||
| 574 | |||
| 575 | DBG("v=%d p=%d", ctrl->v_level, ctrl->p_level); | ||
| 576 | |||
| 577 | value0 = vm_pre_emphasis[(int)(ctrl->v_level)][(int)(ctrl->p_level)]; | ||
| 578 | value1 = vm_voltage_swing[(int)(ctrl->v_level)][(int)(ctrl->p_level)]; | ||
| 579 | |||
| 580 | /* Configure host and panel only if both values are allowed */ | ||
| 581 | if (value0 != 0xFF && value1 != 0xFF) { | ||
| 582 | msm_edp_phy_vm_pe_cfg(ctrl->phy, value0, value1); | ||
| 583 | return edp_lane_set_write(ctrl, ctrl->v_level, ctrl->p_level); | ||
| 584 | } | ||
| 585 | |||
| 586 | return -EINVAL; | ||
| 587 | } | ||
| 588 | |||
| 589 | static int edp_start_link_train_1(struct edp_ctrl *ctrl) | ||
| 590 | { | ||
| 591 | u8 link_status[DP_LINK_STATUS_SIZE]; | ||
| 592 | u8 old_v_level; | ||
| 593 | int tries; | ||
| 594 | int ret; | ||
| 595 | int rlen; | ||
| 596 | |||
| 597 | DBG(""); | ||
| 598 | |||
| 599 | edp_host_train_set(ctrl, DP_TRAINING_PATTERN_1); | ||
| 600 | ret = edp_voltage_pre_emphasise_set(ctrl); | ||
| 601 | if (ret) | ||
| 602 | return ret; | ||
| 603 | ret = edp_train_pattern_set_write(ctrl, | ||
| 604 | DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN); | ||
| 605 | if (ret) | ||
| 606 | return ret; | ||
| 607 | |||
| 608 | tries = 0; | ||
| 609 | old_v_level = ctrl->v_level; | ||
| 610 | while (1) { | ||
| 611 | drm_dp_link_train_clock_recovery_delay(ctrl->drm_aux, ctrl->dpcd); | ||
| 612 | |||
| 613 | rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); | ||
| 614 | if (rlen < DP_LINK_STATUS_SIZE) { | ||
| 615 | pr_err("%s: read link status failed\n", __func__); | ||
| 616 | return -ENOLINK; | ||
| 617 | } | ||
| 618 | if (drm_dp_clock_recovery_ok(link_status, ctrl->lane_cnt)) { | ||
| 619 | ret = 0; | ||
| 620 | break; | ||
| 621 | } | ||
| 622 | |||
| 623 | if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) { | ||
| 624 | ret = -1; | ||
| 625 | break; | ||
| 626 | } | ||
| 627 | |||
| 628 | if (old_v_level == ctrl->v_level) { | ||
| 629 | tries++; | ||
| 630 | if (tries >= 5) { | ||
| 631 | ret = -1; | ||
| 632 | break; | ||
| 633 | } | ||
| 634 | } else { | ||
| 635 | tries = 0; | ||
| 636 | old_v_level = ctrl->v_level; | ||
| 637 | } | ||
| 638 | |||
| 639 | edp_sink_train_set_adjust(ctrl, link_status); | ||
| 640 | ret = edp_voltage_pre_emphasise_set(ctrl); | ||
| 641 | if (ret) | ||
| 642 | return ret; | ||
| 643 | } | ||
| 644 | |||
| 645 | return ret; | ||
| 646 | } | ||
| 647 | |||
| 648 | static int edp_start_link_train_2(struct edp_ctrl *ctrl) | ||
| 649 | { | ||
| 650 | u8 link_status[DP_LINK_STATUS_SIZE]; | ||
| 651 | int tries = 0; | ||
| 652 | int ret; | ||
| 653 | int rlen; | ||
| 654 | |||
| 655 | DBG(""); | ||
| 656 | |||
| 657 | edp_host_train_set(ctrl, DP_TRAINING_PATTERN_2); | ||
| 658 | ret = edp_voltage_pre_emphasise_set(ctrl); | ||
| 659 | if (ret) | ||
| 660 | return ret; | ||
| 661 | |||
| 662 | ret = edp_train_pattern_set_write(ctrl, | ||
| 663 | DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN); | ||
| 664 | if (ret) | ||
| 665 | return ret; | ||
| 666 | |||
| 667 | while (1) { | ||
| 668 | drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); | ||
| 669 | |||
| 670 | rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status); | ||
| 671 | if (rlen < DP_LINK_STATUS_SIZE) { | ||
| 672 | pr_err("%s: read link status failed\n", __func__); | ||
| 673 | return -ENOLINK; | ||
| 674 | } | ||
| 675 | if (drm_dp_channel_eq_ok(link_status, ctrl->lane_cnt)) { | ||
| 676 | ret = 0; | ||
| 677 | break; | ||
| 678 | } | ||
| 679 | |||
| 680 | tries++; | ||
| 681 | if (tries > 10) { | ||
| 682 | ret = -1; | ||
| 683 | break; | ||
| 684 | } | ||
| 685 | |||
| 686 | edp_sink_train_set_adjust(ctrl, link_status); | ||
| 687 | ret = edp_voltage_pre_emphasise_set(ctrl); | ||
| 688 | if (ret) | ||
| 689 | return ret; | ||
| 690 | } | ||
| 691 | |||
| 692 | return ret; | ||
| 693 | } | ||
| 694 | |||
| 695 | static int edp_link_rate_down_shift(struct edp_ctrl *ctrl) | ||
| 696 | { | ||
| 697 | u32 prate, lrate, bpp; | ||
| 698 | u8 rate, lane, max_lane; | ||
| 699 | int changed = 0; | ||
| 700 | |||
| 701 | rate = ctrl->link_rate; | ||
| 702 | lane = ctrl->lane_cnt; | ||
| 703 | max_lane = drm_dp_max_lane_count(ctrl->dpcd); | ||
| 704 | |||
| 705 | bpp = ctrl->color_depth * 3; | ||
| 706 | prate = ctrl->pixel_rate; | ||
| 707 | prate *= bpp; | ||
| 708 | prate /= 8; /* in kByte */ | ||
| 709 | |||
| 710 | if (rate > DP_LINK_BW_1_62 && rate <= EDP_LINK_BW_MAX) { | ||
| 711 | rate -= 4; /* reduce rate */ | ||
| 712 | changed++; | ||
| 713 | } | ||
| 714 | |||
| 715 | if (changed) { | ||
| 716 | if (lane >= 1 && lane < max_lane) | ||
| 717 | lane <<= 1; /* increase lane */ | ||
| 718 | |||
| 719 | lrate = 270000; /* in kHz */ | ||
| 720 | lrate *= rate; | ||
| 721 | lrate /= 10; /* kByte, 10 bits --> 8 bits */ | ||
| 722 | lrate *= lane; | ||
| 723 | |||
| 724 | DBG("new lrate=%u prate=%u(kHz) rate=%d lane=%d p=%u b=%d", | ||
| 725 | lrate, prate, rate, lane, | ||
| 726 | ctrl->pixel_rate, | ||
| 727 | bpp); | ||
| 728 | |||
| 729 | if (lrate > prate) { | ||
| 730 | ctrl->link_rate = rate; | ||
| 731 | ctrl->lane_cnt = lane; | ||
| 732 | DBG("new rate=%d %d", rate, lane); | ||
| 733 | return 0; | ||
| 734 | } | ||
| 735 | } | ||
| 736 | |||
| 737 | return -EINVAL; | ||
| 738 | } | ||
| 739 | |||
| 740 | static int edp_clear_training_pattern(struct edp_ctrl *ctrl) | ||
| 741 | { | ||
| 742 | int ret; | ||
| 743 | |||
| 744 | ret = edp_train_pattern_set_write(ctrl, 0); | ||
| 745 | |||
| 746 | drm_dp_link_train_channel_eq_delay(ctrl->drm_aux, ctrl->dpcd); | ||
| 747 | |||
| 748 | return ret; | ||
| 749 | } | ||
| 750 | |||
| 751 | static int edp_do_link_train(struct edp_ctrl *ctrl) | ||
| 752 | { | ||
| 753 | u8 values[2]; | ||
| 754 | int ret; | ||
| 755 | |||
| 756 | DBG(""); | ||
| 757 | /* | ||
| 758 | * Set the current link rate and lane cnt to panel. They may have been | ||
| 759 | * adjusted and the values are different from them in DPCD CAP | ||
| 760 | */ | ||
| 761 | values[0] = ctrl->lane_cnt; | ||
| 762 | values[1] = ctrl->link_rate; | ||
| 763 | |||
| 764 | if (drm_dp_enhanced_frame_cap(ctrl->dpcd)) | ||
| 765 | values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN; | ||
| 766 | |||
| 767 | if (drm_dp_dpcd_write(ctrl->drm_aux, DP_LINK_BW_SET, values, | ||
| 768 | sizeof(values)) < 0) | ||
| 769 | return EDP_TRAIN_FAIL; | ||
| 770 | |||
| 771 | ctrl->v_level = 0; /* start from default level */ | ||
| 772 | ctrl->p_level = 0; | ||
| 773 | |||
| 774 | edp_state_ctrl(ctrl, 0); | ||
| 775 | if (edp_clear_training_pattern(ctrl)) | ||
| 776 | return EDP_TRAIN_FAIL; | ||
| 777 | |||
| 778 | ret = edp_start_link_train_1(ctrl); | ||
| 779 | if (ret < 0) { | ||
| 780 | if (edp_link_rate_down_shift(ctrl) == 0) { | ||
| 781 | DBG("link reconfig"); | ||
| 782 | ret = EDP_TRAIN_RECONFIG; | ||
| 783 | goto clear; | ||
| 784 | } else { | ||
| 785 | pr_err("%s: Training 1 failed", __func__); | ||
| 786 | ret = EDP_TRAIN_FAIL; | ||
| 787 | goto clear; | ||
| 788 | } | ||
| 789 | } | ||
| 790 | DBG("Training 1 completed successfully"); | ||
| 791 | |||
| 792 | edp_state_ctrl(ctrl, 0); | ||
| 793 | if (edp_clear_training_pattern(ctrl)) | ||
| 794 | return EDP_TRAIN_FAIL; | ||
| 795 | |||
| 796 | ret = edp_start_link_train_2(ctrl); | ||
| 797 | if (ret < 0) { | ||
| 798 | if (edp_link_rate_down_shift(ctrl) == 0) { | ||
| 799 | DBG("link reconfig"); | ||
| 800 | ret = EDP_TRAIN_RECONFIG; | ||
| 801 | goto clear; | ||
| 802 | } else { | ||
| 803 | pr_err("%s: Training 2 failed", __func__); | ||
| 804 | ret = EDP_TRAIN_FAIL; | ||
| 805 | goto clear; | ||
| 806 | } | ||
| 807 | } | ||
| 808 | DBG("Training 2 completed successfully"); | ||
| 809 | |||
| 810 | edp_state_ctrl(ctrl, EDP_STATE_CTRL_SEND_VIDEO); | ||
| 811 | clear: | ||
| 812 | edp_clear_training_pattern(ctrl); | ||
| 813 | |||
| 814 | return ret; | ||
| 815 | } | ||
| 816 | |||
| 817 | static void edp_clock_synchrous(struct edp_ctrl *ctrl, int sync) | ||
| 818 | { | ||
| 819 | u32 data; | ||
| 820 | enum edp_color_depth depth; | ||
| 821 | |||
| 822 | data = edp_read(ctrl->base + REG_EDP_MISC1_MISC0); | ||
| 823 | |||
| 824 | if (sync) | ||
| 825 | data |= EDP_MISC1_MISC0_SYNC; | ||
| 826 | else | ||
| 827 | data &= ~EDP_MISC1_MISC0_SYNC; | ||
| 828 | |||
| 829 | /* only legacy rgb mode supported */ | ||
| 830 | depth = EDP_6BIT; /* Default */ | ||
| 831 | if (ctrl->color_depth == 8) | ||
| 832 | depth = EDP_8BIT; | ||
| 833 | else if (ctrl->color_depth == 10) | ||
| 834 | depth = EDP_10BIT; | ||
| 835 | else if (ctrl->color_depth == 12) | ||
| 836 | depth = EDP_12BIT; | ||
| 837 | else if (ctrl->color_depth == 16) | ||
| 838 | depth = EDP_16BIT; | ||
| 839 | |||
| 840 | data |= EDP_MISC1_MISC0_COLOR(depth); | ||
| 841 | |||
| 842 | edp_write(ctrl->base + REG_EDP_MISC1_MISC0, data); | ||
| 843 | } | ||
| 844 | |||
| 845 | static int edp_sw_mvid_nvid(struct edp_ctrl *ctrl, u32 m, u32 n) | ||
| 846 | { | ||
| 847 | u32 n_multi, m_multi = 5; | ||
| 848 | |||
| 849 | if (ctrl->link_rate == DP_LINK_BW_1_62) { | ||
| 850 | n_multi = 1; | ||
| 851 | } else if (ctrl->link_rate == DP_LINK_BW_2_7) { | ||
| 852 | n_multi = 2; | ||
| 853 | } else { | ||
| 854 | pr_err("%s: Invalid link rate, %d\n", __func__, | ||
| 855 | ctrl->link_rate); | ||
| 856 | return -EINVAL; | ||
| 857 | } | ||
| 858 | |||
| 859 | edp_write(ctrl->base + REG_EDP_SOFTWARE_MVID, m * m_multi); | ||
| 860 | edp_write(ctrl->base + REG_EDP_SOFTWARE_NVID, n * n_multi); | ||
| 861 | |||
| 862 | return 0; | ||
| 863 | } | ||
| 864 | |||
| 865 | static void edp_mainlink_ctrl(struct edp_ctrl *ctrl, int enable) | ||
| 866 | { | ||
| 867 | u32 data = 0; | ||
| 868 | |||
| 869 | edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, EDP_MAINLINK_CTRL_RESET); | ||
| 870 | /* Make sure fully reset */ | ||
| 871 | wmb(); | ||
| 872 | usleep_range(500, 1000); | ||
| 873 | |||
| 874 | if (enable) | ||
| 875 | data |= EDP_MAINLINK_CTRL_ENABLE; | ||
| 876 | |||
| 877 | edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, data); | ||
| 878 | } | ||
| 879 | |||
| 880 | static void edp_ctrl_phy_aux_enable(struct edp_ctrl *ctrl, int enable) | ||
| 881 | { | ||
| 882 | if (enable) { | ||
| 883 | edp_regulator_enable(ctrl); | ||
| 884 | edp_clk_enable(ctrl, EDP_CLK_MASK_AUX_CHAN); | ||
| 885 | msm_edp_phy_ctrl(ctrl->phy, 1); | ||
| 886 | msm_edp_aux_ctrl(ctrl->aux, 1); | ||
| 887 | gpiod_set_value(ctrl->panel_en_gpio, 1); | ||
| 888 | } else { | ||
| 889 | gpiod_set_value(ctrl->panel_en_gpio, 0); | ||
| 890 | msm_edp_aux_ctrl(ctrl->aux, 0); | ||
| 891 | msm_edp_phy_ctrl(ctrl->phy, 0); | ||
| 892 | edp_clk_disable(ctrl, EDP_CLK_MASK_AUX_CHAN); | ||
| 893 | edp_regulator_disable(ctrl); | ||
| 894 | } | ||
| 895 | } | ||
| 896 | |||
| 897 | static void edp_ctrl_link_enable(struct edp_ctrl *ctrl, int enable) | ||
| 898 | { | ||
| 899 | u32 m, n; | ||
| 900 | |||
| 901 | if (enable) { | ||
| 902 | /* Enable link channel clocks */ | ||
| 903 | edp_clk_enable(ctrl, EDP_CLK_MASK_LINK_CHAN); | ||
| 904 | |||
| 905 | msm_edp_phy_lane_power_ctrl(ctrl->phy, true, ctrl->lane_cnt); | ||
| 906 | |||
| 907 | msm_edp_phy_vm_pe_init(ctrl->phy); | ||
| 908 | |||
| 909 | /* Make sure phy is programed */ | ||
| 910 | wmb(); | ||
| 911 | msm_edp_phy_ready(ctrl->phy); | ||
| 912 | |||
| 913 | edp_config_ctrl(ctrl); | ||
| 914 | msm_edp_ctrl_pixel_clock_valid(ctrl, ctrl->pixel_rate, &m, &n); | ||
| 915 | edp_sw_mvid_nvid(ctrl, m, n); | ||
| 916 | edp_mainlink_ctrl(ctrl, 1); | ||
| 917 | } else { | ||
| 918 | edp_mainlink_ctrl(ctrl, 0); | ||
| 919 | |||
| 920 | msm_edp_phy_lane_power_ctrl(ctrl->phy, false, 0); | ||
| 921 | edp_clk_disable(ctrl, EDP_CLK_MASK_LINK_CHAN); | ||
| 922 | } | ||
| 923 | } | ||
| 924 | |||
| 925 | static int edp_ctrl_training(struct edp_ctrl *ctrl) | ||
| 926 | { | ||
| 927 | int ret; | ||
| 928 | |||
| 929 | /* Do link training only when power is on */ | ||
| 930 | if (!ctrl->power_on) | ||
| 931 | return -EINVAL; | ||
| 932 | |||
| 933 | train_start: | ||
| 934 | ret = edp_do_link_train(ctrl); | ||
| 935 | if (ret == EDP_TRAIN_RECONFIG) { | ||
| 936 | /* Re-configure main link */ | ||
| 937 | edp_ctrl_irq_enable(ctrl, 0); | ||
| 938 | edp_ctrl_link_enable(ctrl, 0); | ||
| 939 | msm_edp_phy_ctrl(ctrl->phy, 0); | ||
| 940 | |||
| 941 | /* Make sure link is fully disabled */ | ||
| 942 | wmb(); | ||
| 943 | usleep_range(500, 1000); | ||
| 944 | |||
| 945 | msm_edp_phy_ctrl(ctrl->phy, 1); | ||
| 946 | edp_ctrl_link_enable(ctrl, 1); | ||
| 947 | edp_ctrl_irq_enable(ctrl, 1); | ||
| 948 | goto train_start; | ||
| 949 | } | ||
| 950 | |||
| 951 | return ret; | ||
| 952 | } | ||
| 953 | |||
| 954 | static void edp_ctrl_on_worker(struct work_struct *work) | ||
| 955 | { | ||
| 956 | struct edp_ctrl *ctrl = container_of( | ||
| 957 | work, struct edp_ctrl, on_work); | ||
| 958 | u8 value; | ||
| 959 | int ret; | ||
| 960 | |||
| 961 | mutex_lock(&ctrl->dev_mutex); | ||
| 962 | |||
| 963 | if (ctrl->power_on) { | ||
| 964 | DBG("already on"); | ||
| 965 | goto unlock_ret; | ||
| 966 | } | ||
| 967 | |||
| 968 | edp_ctrl_phy_aux_enable(ctrl, 1); | ||
| 969 | edp_ctrl_link_enable(ctrl, 1); | ||
| 970 | |||
| 971 | edp_ctrl_irq_enable(ctrl, 1); | ||
| 972 | |||
| 973 | /* DP_SET_POWER register is only available on DPCD v1.1 and later */ | ||
| 974 | if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { | ||
| 975 | ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); | ||
| 976 | if (ret < 0) | ||
| 977 | goto fail; | ||
| 978 | |||
| 979 | value &= ~DP_SET_POWER_MASK; | ||
| 980 | value |= DP_SET_POWER_D0; | ||
| 981 | |||
| 982 | ret = drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); | ||
| 983 | if (ret < 0) | ||
| 984 | goto fail; | ||
| 985 | |||
| 986 | /* | ||
| 987 | * According to the DP 1.1 specification, a "Sink Device must | ||
| 988 | * exit the power saving state within 1 ms" (Section 2.5.3.1, | ||
| 989 | * Table 5-52, "Sink Control Field" (register 0x600). | ||
| 990 | */ | ||
| 991 | usleep_range(1000, 2000); | ||
| 992 | } | ||
| 993 | |||
| 994 | ctrl->power_on = true; | ||
| 995 | |||
| 996 | /* Start link training */ | ||
| 997 | ret = edp_ctrl_training(ctrl); | ||
| 998 | if (ret != EDP_TRAIN_SUCCESS) | ||
| 999 | goto fail; | ||
| 1000 | |||
| 1001 | DBG("DONE"); | ||
| 1002 | goto unlock_ret; | ||
| 1003 | |||
| 1004 | fail: | ||
| 1005 | edp_ctrl_irq_enable(ctrl, 0); | ||
| 1006 | edp_ctrl_link_enable(ctrl, 0); | ||
| 1007 | edp_ctrl_phy_aux_enable(ctrl, 0); | ||
| 1008 | ctrl->power_on = false; | ||
| 1009 | unlock_ret: | ||
| 1010 | mutex_unlock(&ctrl->dev_mutex); | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static void edp_ctrl_off_worker(struct work_struct *work) | ||
| 1014 | { | ||
| 1015 | struct edp_ctrl *ctrl = container_of( | ||
| 1016 | work, struct edp_ctrl, off_work); | ||
| 1017 | unsigned long time_left; | ||
| 1018 | |||
| 1019 | mutex_lock(&ctrl->dev_mutex); | ||
| 1020 | |||
| 1021 | if (!ctrl->power_on) { | ||
| 1022 | DBG("already off"); | ||
| 1023 | goto unlock_ret; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | reinit_completion(&ctrl->idle_comp); | ||
| 1027 | edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE); | ||
| 1028 | |||
| 1029 | time_left = wait_for_completion_timeout(&ctrl->idle_comp, | ||
| 1030 | msecs_to_jiffies(500)); | ||
| 1031 | if (!time_left) | ||
| 1032 | DBG("%s: idle pattern timedout\n", __func__); | ||
| 1033 | |||
| 1034 | edp_state_ctrl(ctrl, 0); | ||
| 1035 | |||
| 1036 | /* DP_SET_POWER register is only available on DPCD v1.1 and later */ | ||
| 1037 | if (ctrl->dpcd[DP_DPCD_REV] >= 0x11) { | ||
| 1038 | u8 value; | ||
| 1039 | int ret; | ||
| 1040 | |||
| 1041 | ret = drm_dp_dpcd_readb(ctrl->drm_aux, DP_SET_POWER, &value); | ||
| 1042 | if (ret > 0) { | ||
| 1043 | value &= ~DP_SET_POWER_MASK; | ||
| 1044 | value |= DP_SET_POWER_D3; | ||
| 1045 | |||
| 1046 | drm_dp_dpcd_writeb(ctrl->drm_aux, DP_SET_POWER, value); | ||
| 1047 | } | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | edp_ctrl_irq_enable(ctrl, 0); | ||
| 1051 | |||
| 1052 | edp_ctrl_link_enable(ctrl, 0); | ||
| 1053 | |||
| 1054 | edp_ctrl_phy_aux_enable(ctrl, 0); | ||
| 1055 | |||
| 1056 | ctrl->power_on = false; | ||
| 1057 | |||
| 1058 | unlock_ret: | ||
| 1059 | mutex_unlock(&ctrl->dev_mutex); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl) | ||
| 1063 | { | ||
| 1064 | u32 isr1, isr2, mask1, mask2; | ||
| 1065 | u32 ack; | ||
| 1066 | |||
| 1067 | DBG(""); | ||
| 1068 | spin_lock(&ctrl->irq_lock); | ||
| 1069 | isr1 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_1); | ||
| 1070 | isr2 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_2); | ||
| 1071 | |||
| 1072 | mask1 = isr1 & EDP_INTR_MASK1; | ||
| 1073 | mask2 = isr2 & EDP_INTR_MASK2; | ||
| 1074 | |||
| 1075 | isr1 &= ~mask1; /* remove masks bit */ | ||
| 1076 | isr2 &= ~mask2; | ||
| 1077 | |||
| 1078 | DBG("isr=%x mask=%x isr2=%x mask2=%x", | ||
| 1079 | isr1, mask1, isr2, mask2); | ||
| 1080 | |||
| 1081 | ack = isr1 & EDP_INTR_STATUS1; | ||
| 1082 | ack <<= 1; /* ack bits */ | ||
| 1083 | ack |= mask1; | ||
| 1084 | edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, ack); | ||
| 1085 | |||
| 1086 | ack = isr2 & EDP_INTR_STATUS2; | ||
| 1087 | ack <<= 1; /* ack bits */ | ||
| 1088 | ack |= mask2; | ||
| 1089 | edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, ack); | ||
| 1090 | spin_unlock(&ctrl->irq_lock); | ||
| 1091 | |||
| 1092 | if (isr1 & EDP_INTERRUPT_REG_1_HPD) | ||
| 1093 | DBG("edp_hpd"); | ||
| 1094 | |||
| 1095 | if (isr2 & EDP_INTERRUPT_REG_2_READY_FOR_VIDEO) | ||
| 1096 | DBG("edp_video_ready"); | ||
| 1097 | |||
| 1098 | if (isr2 & EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT) { | ||
| 1099 | DBG("idle_patterns_sent"); | ||
| 1100 | complete(&ctrl->idle_comp); | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | msm_edp_aux_irq(ctrl->aux, isr1); | ||
| 1104 | |||
| 1105 | return IRQ_HANDLED; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on) | ||
| 1109 | { | ||
| 1110 | if (on) | ||
| 1111 | queue_work(ctrl->workqueue, &ctrl->on_work); | ||
| 1112 | else | ||
| 1113 | queue_work(ctrl->workqueue, &ctrl->off_work); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | int msm_edp_ctrl_init(struct msm_edp *edp) | ||
| 1117 | { | ||
| 1118 | struct edp_ctrl *ctrl = NULL; | ||
| 1119 | struct device *dev; | ||
| 1120 | int ret; | ||
| 1121 | |||
| 1122 | if (!edp) { | ||
| 1123 | pr_err("%s: edp is NULL!\n", __func__); | ||
| 1124 | return -EINVAL; | ||
| 1125 | } | ||
| 1126 | |||
| 1127 | dev = &edp->pdev->dev; | ||
| 1128 | ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL); | ||
| 1129 | if (!ctrl) | ||
| 1130 | return -ENOMEM; | ||
| 1131 | |||
| 1132 | edp->ctrl = ctrl; | ||
| 1133 | ctrl->pdev = edp->pdev; | ||
| 1134 | |||
| 1135 | ctrl->base = msm_ioremap(ctrl->pdev, "edp", "eDP"); | ||
| 1136 | if (IS_ERR(ctrl->base)) | ||
| 1137 | return PTR_ERR(ctrl->base); | ||
| 1138 | |||
| 1139 | /* Get regulator, clock, gpio, pwm */ | ||
| 1140 | ret = edp_regulator_init(ctrl); | ||
| 1141 | if (ret) { | ||
| 1142 | pr_err("%s:regulator init fail\n", __func__); | ||
| 1143 | return ret; | ||
| 1144 | } | ||
| 1145 | ret = edp_clk_init(ctrl); | ||
| 1146 | if (ret) { | ||
| 1147 | pr_err("%s:clk init fail\n", __func__); | ||
| 1148 | return ret; | ||
| 1149 | } | ||
| 1150 | ret = edp_gpio_config(ctrl); | ||
| 1151 | if (ret) { | ||
| 1152 | pr_err("%s:failed to configure GPIOs: %d", __func__, ret); | ||
| 1153 | return ret; | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | /* Init aux and phy */ | ||
| 1157 | ctrl->aux = msm_edp_aux_init(edp, ctrl->base, &ctrl->drm_aux); | ||
| 1158 | if (!ctrl->aux || !ctrl->drm_aux) { | ||
| 1159 | pr_err("%s:failed to init aux\n", __func__); | ||
| 1160 | return -ENOMEM; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | ctrl->phy = msm_edp_phy_init(dev, ctrl->base); | ||
| 1164 | if (!ctrl->phy) { | ||
| 1165 | pr_err("%s:failed to init phy\n", __func__); | ||
| 1166 | ret = -ENOMEM; | ||
| 1167 | goto err_destory_aux; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | spin_lock_init(&ctrl->irq_lock); | ||
| 1171 | mutex_init(&ctrl->dev_mutex); | ||
| 1172 | init_completion(&ctrl->idle_comp); | ||
| 1173 | |||
| 1174 | /* setup workqueue */ | ||
| 1175 | ctrl->workqueue = alloc_ordered_workqueue("edp_drm_work", 0); | ||
| 1176 | INIT_WORK(&ctrl->on_work, edp_ctrl_on_worker); | ||
| 1177 | INIT_WORK(&ctrl->off_work, edp_ctrl_off_worker); | ||
| 1178 | |||
| 1179 | return 0; | ||
| 1180 | |||
| 1181 | err_destory_aux: | ||
| 1182 | msm_edp_aux_destroy(dev, ctrl->aux); | ||
| 1183 | ctrl->aux = NULL; | ||
| 1184 | return ret; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl) | ||
| 1188 | { | ||
| 1189 | if (!ctrl) | ||
| 1190 | return; | ||
| 1191 | |||
| 1192 | if (ctrl->workqueue) { | ||
| 1193 | destroy_workqueue(ctrl->workqueue); | ||
| 1194 | ctrl->workqueue = NULL; | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | if (ctrl->aux) { | ||
| 1198 | msm_edp_aux_destroy(&ctrl->pdev->dev, ctrl->aux); | ||
| 1199 | ctrl->aux = NULL; | ||
| 1200 | } | ||
| 1201 | |||
| 1202 | kfree(ctrl->edid); | ||
| 1203 | ctrl->edid = NULL; | ||
| 1204 | |||
| 1205 | mutex_destroy(&ctrl->dev_mutex); | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl) | ||
| 1209 | { | ||
| 1210 | mutex_lock(&ctrl->dev_mutex); | ||
| 1211 | DBG("connect status = %d", ctrl->edp_connected); | ||
| 1212 | if (ctrl->edp_connected) { | ||
| 1213 | mutex_unlock(&ctrl->dev_mutex); | ||
| 1214 | return true; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | if (!ctrl->power_on) { | ||
| 1218 | edp_ctrl_phy_aux_enable(ctrl, 1); | ||
| 1219 | edp_ctrl_irq_enable(ctrl, 1); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd, | ||
| 1223 | DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) { | ||
| 1224 | pr_err("%s: AUX channel is NOT ready\n", __func__); | ||
| 1225 | memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE); | ||
| 1226 | } else { | ||
| 1227 | ctrl->edp_connected = true; | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | if (!ctrl->power_on) { | ||
| 1231 | edp_ctrl_irq_enable(ctrl, 0); | ||
| 1232 | edp_ctrl_phy_aux_enable(ctrl, 0); | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | DBG("exit: connect status=%d", ctrl->edp_connected); | ||
| 1236 | |||
| 1237 | mutex_unlock(&ctrl->dev_mutex); | ||
| 1238 | |||
| 1239 | return ctrl->edp_connected; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl, | ||
| 1243 | struct drm_connector *connector, struct edid **edid) | ||
| 1244 | { | ||
| 1245 | mutex_lock(&ctrl->dev_mutex); | ||
| 1246 | |||
| 1247 | if (ctrl->edid) { | ||
| 1248 | if (edid) { | ||
| 1249 | DBG("Just return edid buffer"); | ||
| 1250 | *edid = ctrl->edid; | ||
| 1251 | } | ||
| 1252 | goto unlock_ret; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | if (!ctrl->power_on) { | ||
| 1256 | edp_ctrl_phy_aux_enable(ctrl, 1); | ||
| 1257 | edp_ctrl_irq_enable(ctrl, 1); | ||
| 1258 | } | ||
| 1259 | |||
| 1260 | /* Initialize link rate as panel max link rate */ | ||
| 1261 | ctrl->link_rate = ctrl->dpcd[DP_MAX_LINK_RATE]; | ||
| 1262 | |||
| 1263 | ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc); | ||
| 1264 | if (!ctrl->edid) { | ||
| 1265 | pr_err("%s: edid read fail\n", __func__); | ||
| 1266 | goto disable_ret; | ||
| 1267 | } | ||
| 1268 | |||
| 1269 | if (edid) | ||
| 1270 | *edid = ctrl->edid; | ||
| 1271 | |||
| 1272 | disable_ret: | ||
| 1273 | if (!ctrl->power_on) { | ||
| 1274 | edp_ctrl_irq_enable(ctrl, 0); | ||
| 1275 | edp_ctrl_phy_aux_enable(ctrl, 0); | ||
| 1276 | } | ||
| 1277 | unlock_ret: | ||
| 1278 | mutex_unlock(&ctrl->dev_mutex); | ||
| 1279 | return 0; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl, | ||
| 1283 | const struct drm_display_mode *mode, | ||
| 1284 | const struct drm_display_info *info) | ||
| 1285 | { | ||
| 1286 | u32 hstart_from_sync, vstart_from_sync; | ||
| 1287 | u32 data; | ||
| 1288 | int ret = 0; | ||
| 1289 | |||
| 1290 | mutex_lock(&ctrl->dev_mutex); | ||
| 1291 | /* | ||
| 1292 | * Need to keep color depth, pixel rate and | ||
| 1293 | * interlaced information in ctrl context | ||
| 1294 | */ | ||
| 1295 | ctrl->color_depth = info->bpc; | ||
| 1296 | ctrl->pixel_rate = mode->clock; | ||
| 1297 | ctrl->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); | ||
| 1298 | |||
| 1299 | /* Fill initial link config based on passed in timing */ | ||
| 1300 | edp_fill_link_cfg(ctrl); | ||
| 1301 | |||
| 1302 | if (edp_clk_enable(ctrl, EDP_CLK_MASK_AHB)) { | ||
| 1303 | pr_err("%s, fail to prepare enable ahb clk\n", __func__); | ||
| 1304 | ret = -EINVAL; | ||
| 1305 | goto unlock_ret; | ||
| 1306 | } | ||
| 1307 | edp_clock_synchrous(ctrl, 1); | ||
| 1308 | |||
| 1309 | /* Configure eDP timing to HW */ | ||
| 1310 | edp_write(ctrl->base + REG_EDP_TOTAL_HOR_VER, | ||
| 1311 | EDP_TOTAL_HOR_VER_HORIZ(mode->htotal) | | ||
| 1312 | EDP_TOTAL_HOR_VER_VERT(mode->vtotal)); | ||
| 1313 | |||
| 1314 | vstart_from_sync = mode->vtotal - mode->vsync_start; | ||
| 1315 | hstart_from_sync = mode->htotal - mode->hsync_start; | ||
| 1316 | edp_write(ctrl->base + REG_EDP_START_HOR_VER_FROM_SYNC, | ||
| 1317 | EDP_START_HOR_VER_FROM_SYNC_HORIZ(hstart_from_sync) | | ||
| 1318 | EDP_START_HOR_VER_FROM_SYNC_VERT(vstart_from_sync)); | ||
| 1319 | |||
| 1320 | data = EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT( | ||
| 1321 | mode->vsync_end - mode->vsync_start); | ||
| 1322 | data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ( | ||
| 1323 | mode->hsync_end - mode->hsync_start); | ||
| 1324 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
| 1325 | data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC; | ||
| 1326 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
| 1327 | data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC; | ||
| 1328 | edp_write(ctrl->base + REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY, data); | ||
| 1329 | |||
| 1330 | edp_write(ctrl->base + REG_EDP_ACTIVE_HOR_VER, | ||
| 1331 | EDP_ACTIVE_HOR_VER_HORIZ(mode->hdisplay) | | ||
| 1332 | EDP_ACTIVE_HOR_VER_VERT(mode->vdisplay)); | ||
| 1333 | |||
| 1334 | edp_clk_disable(ctrl, EDP_CLK_MASK_AHB); | ||
| 1335 | |||
| 1336 | unlock_ret: | ||
| 1337 | mutex_unlock(&ctrl->dev_mutex); | ||
| 1338 | return ret; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl, | ||
| 1342 | u32 pixel_rate, u32 *pm, u32 *pn) | ||
| 1343 | { | ||
| 1344 | const struct edp_pixel_clk_div *divs; | ||
| 1345 | u32 err = 1; /* 1% error tolerance */ | ||
| 1346 | u32 clk_err; | ||
| 1347 | int i; | ||
| 1348 | |||
| 1349 | if (ctrl->link_rate == DP_LINK_BW_1_62) { | ||
| 1350 | divs = clk_divs[0]; | ||
| 1351 | } else if (ctrl->link_rate == DP_LINK_BW_2_7) { | ||
| 1352 | divs = clk_divs[1]; | ||
| 1353 | } else { | ||
| 1354 | pr_err("%s: Invalid link rate,%d\n", __func__, ctrl->link_rate); | ||
| 1355 | return false; | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | for (i = 0; i < EDP_PIXEL_CLK_NUM; i++) { | ||
| 1359 | clk_err = abs(divs[i].rate - pixel_rate); | ||
| 1360 | if ((divs[i].rate * err / 100) >= clk_err) { | ||
| 1361 | if (pm) | ||
| 1362 | *pm = divs[i].m; | ||
| 1363 | if (pn) | ||
| 1364 | *pn = divs[i].n; | ||
| 1365 | return true; | ||
| 1366 | } | ||
| 1367 | } | ||
| 1368 | |||
| 1369 | DBG("pixel clock %d(kHz) not supported", pixel_rate); | ||
| 1370 | |||
| 1371 | return false; | ||
| 1372 | } | ||
| 1373 | |||
| @@ -374,12 +374,20 @@ static int mxsfb_remove(struct platform_device *pdev) · 373 unmodified lines | |||
| 374 | struct drm_device *drm = platform_get_drvdata(pdev); | 374 | struct drm_device *drm = platform_get_drvdata(pdev); |
| 375 | 375 | ||
| 376 | drm_dev_unregister(drm); | 376 | drm_dev_unregister(drm); |
| 377 | drm_atomic_helper_shutdown(drm); | ||
| 377 | mxsfb_unload(drm); | 378 | mxsfb_unload(drm); |
| 378 | drm_dev_put(drm); | 379 | drm_dev_put(drm); |
| 379 | 380 | ||
| 380 | return 0; | 381 | return 0; |
| 381 | } | 382 | } |
| 382 | 383 | ||
| 384 | static void mxsfb_shutdown(struct platform_device *pdev) | ||
| 385 | { | ||
| 386 | struct drm_device *drm = platform_get_drvdata(pdev); | ||
| 387 | |||
| 388 | drm_atomic_helper_shutdown(drm); | ||
| 389 | } | ||
| 390 | |||
| 383 | #ifdef CONFIG_PM_SLEEP | 391 | #ifdef CONFIG_PM_SLEEP |
| 384 | static int mxsfb_suspend(struct device *dev) | 392 | static int mxsfb_suspend(struct device *dev) |
| 385 | { | 393 | { |
| @@ -403,6 +411,7 @@ static const struct dev_pm_ops mxsfb_pm_ops = { · 17 unmodified lines | |||
| 403 | static struct platform_driver mxsfb_platform_driver = { | 411 | static struct platform_driver mxsfb_platform_driver = { |
| 404 | .probe = mxsfb_probe, | 412 | .probe = mxsfb_probe, |
| 405 | .remove = mxsfb_remove, | 413 | .remove = mxsfb_remove, |
| 414 | .shutdown = mxsfb_shutdown, | ||
| 406 | .driver = { | 415 | .driver = { |
| 407 | .name = "mxsfb", | 416 | .name = "mxsfb", |
| 408 | .of_match_table = mxsfb_dt_ids, | 417 | .of_match_table = mxsfb_dt_ids, |
| @@ -4,6 +4,7 @@ config DRM_NOUVEAU · 3 unmodified lines | |||
| 4 | depends on DRM && PCI && MMU | 4 | depends on DRM && PCI && MMU |
| 5 | select IOMMU_API | 5 | select IOMMU_API |
| 6 | select FW_LOADER | 6 | select FW_LOADER |
| 7 | select DRM_DP_HELPER | ||
| 7 | select DRM_KMS_HELPER | 8 | select DRM_KMS_HELPER |
| 8 | select DRM_TTM | 9 | select DRM_TTM |
| 9 | select DRM_TTM_HELPER | 10 | select DRM_TTM_HELPER |
| @@ -35,7 +35,7 @@ · 34 unmodified lines | |||
| 35 | 35 | ||
| 36 | #include <drm/drm_atomic.h> | 36 | #include <drm/drm_atomic.h> |
| 37 | #include <drm/drm_atomic_helper.h> | 37 | #include <drm/drm_atomic_helper.h> |
| 38 | #include <drm/drm_dp_helper.h> | 38 | #include <drm/dp/drm_dp_helper.h> |
| 39 | #include <drm/drm_edid.h> | 39 | #include <drm/drm_edid.h> |
| 40 | #include <drm/drm_fb_helper.h> | 40 | #include <drm/drm_fb_helper.h> |
| 41 | #include <drm/drm_plane_helper.h> | 41 | #include <drm/drm_plane_helper.h> |
| @@ -36,7 +36,7 @@ · 35 unmodified lines | |||
| 36 | #include <drm/drm_crtc.h> | 36 | #include <drm/drm_crtc.h> |
| 37 | #include <drm/drm_edid.h> | 37 | #include <drm/drm_edid.h> |
| 38 | #include <drm/drm_encoder.h> | 38 | #include <drm/drm_encoder.h> |
| 39 | #include <drm/drm_dp_helper.h> | 39 | #include <drm/dp/drm_dp_helper.h> |
| 40 | #include <drm/drm_util.h> | 40 | #include <drm/drm_util.h> |
| 41 | 41 | ||
| 42 | #include "nouveau_crtc.h" | 42 | #include "nouveau_crtc.h" |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | * Authors: Ben Skeggs | 22 | * Authors: Ben Skeggs |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <drm/drm_dp_helper.h> | 25 | #include <drm/dp/drm_dp_helper.h> |
| 26 | 26 | ||
| 27 | #include "nouveau_drv.h" | 27 | #include "nouveau_drv.h" |
| 28 | #include "nouveau_connector.h" | 28 | #include "nouveau_connector.h" |
| @@ -147,6 +147,21 @@ nouveau_dp_detect(struct nouveau_connector *nv_connector, · 118 unmodified lines | |||
| 147 | nv_encoder->dp.link_nr = | 147 | nv_encoder->dp.link_nr = |
| 148 | dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; | 148 | dpcd[DP_MAX_LANE_COUNT] & DP_MAX_LANE_COUNT_MASK; |
| 149 | 149 | ||
| 150 | if (connector->connector_type == DRM_MODE_CONNECTOR_eDP && dpcd[DP_DPCD_REV] >= 0x13) { | ||
| 151 | struct drm_dp_aux *aux = &nv_connector->aux; | ||
| 152 | int ret, i; | ||
| 153 | u8 sink_rates[16]; | ||
| 154 | |||
| 155 | ret = drm_dp_dpcd_read(aux, DP_SUPPORTED_LINK_RATES, sink_rates, sizeof(sink_rates)); | ||
| 156 | if (ret == sizeof(sink_rates)) { | ||
| 157 | for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { | ||
| 158 | int val = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; | ||
| 159 | if (val && (i == 0 || val > nv_encoder->dp.link_bw)) | ||
| 160 | nv_encoder->dp.link_bw = val; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 150 | NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", | 165 | NV_DEBUG(drm, "display: %dx%d dpcd 0x%02x\n", |
| 151 | nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, | 166 | nv_encoder->dp.link_nr, nv_encoder->dp.link_bw, |
| 152 | dpcd[DP_DPCD_REV]); | 167 | dpcd[DP_DPCD_REV]); |
| @@ -30,8 +30,8 @@ · 29 unmodified lines | |||
| 30 | #include <subdev/bios/dcb.h> | 30 | #include <subdev/bios/dcb.h> |
| 31 | 31 | ||
| 32 | #include <drm/drm_encoder_slave.h> | 32 | #include <drm/drm_encoder_slave.h> |
| 33 | #include <drm/drm_dp_helper.h> | 33 | #include <drm/dp/drm_dp_helper.h> |
| 34 | #include <drm/drm_dp_mst_helper.h> | 34 | #include <drm/dp/drm_dp_mst_helper.h> |
| 35 | #include "dispnv04/disp.h" | 35 | #include "dispnv04/disp.h" |
| 36 | struct nv50_head_atom; | 36 | struct nv50_head_atom; |
| 37 | struct nouveau_connector; | 37 | struct nouveau_connector; |
| @@ -162,11 +162,12 @@ nouveau_mem_vram(struct ttm_resource *reg, bool contig, u8 page) · 161 unmodified lines | |||
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | void | 164 | void |
| 165 | nouveau_mem_del(struct ttm_resource *reg) | 165 | nouveau_mem_del(struct ttm_resource_manager *man, struct ttm_resource *reg) |
| 166 | { | 166 | { |
| 167 | struct nouveau_mem *mem = nouveau_mem(reg); | 167 | struct nouveau_mem *mem = nouveau_mem(reg); |
| 168 | 168 | ||
| 169 | nouveau_mem_fini(mem); | 169 | nouveau_mem_fini(mem); |
| 170 | ttm_resource_fini(man, reg); | ||
| 170 | kfree(mem); | 171 | kfree(mem); |
| 171 | } | 172 | } |
| 172 | 173 | ||
| @@ -23,7 +23,8 @@ nouveau_mem(struct ttm_resource *reg) · 22 unmodified lines | |||
| 23 | 23 | ||
| 24 | int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, | 24 | int nouveau_mem_new(struct nouveau_cli *, u8 kind, u8 comp, |
| 25 | struct ttm_resource **); | 25 | struct ttm_resource **); |
| 26 | void nouveau_mem_del(struct ttm_resource *); | 26 | void nouveau_mem_del(struct ttm_resource_manager *man, |
| 27 | struct ttm_resource *); | ||
| 27 | int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); | 28 | int nouveau_mem_vram(struct ttm_resource *, bool contig, u8 page); |
| 28 | int nouveau_mem_host(struct ttm_resource *, struct ttm_tt *); | 29 | int nouveau_mem_host(struct ttm_resource *, struct ttm_tt *); |
| 29 | void nouveau_mem_fini(struct nouveau_mem *); | 30 | void nouveau_mem_fini(struct nouveau_mem *); |
| @@ -36,9 +36,10 @@ · 35 unmodified lines | |||
| 36 | #include <core/tegra.h> | 36 | #include <core/tegra.h> |
| 37 | 37 | ||
| 38 | static void | 38 | static void |
| 39 | nouveau_manager_del(struct ttm_resource_manager *man, struct ttm_resource *reg) | 39 | nouveau_manager_del(struct ttm_resource_manager *man, |
| 40 | struct ttm_resource *reg) | ||
| 40 | { | 41 | { |
| 41 | nouveau_mem_del(reg); | 42 | nouveau_mem_del(man, reg); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | static int | 45 | static int |
| @@ -62,7 +63,7 @@ nouveau_vram_manager_new(struct ttm_resource_manager *man, · 17 unmodified lines | |||
| 62 | 63 | ||
| 63 | ret = nouveau_mem_vram(*res, nvbo->contig, nvbo->page); | 64 | ret = nouveau_mem_vram(*res, nvbo->contig, nvbo->page); |
| 64 | if (ret) { | 65 | if (ret) { |
| 65 | nouveau_mem_del(*res); | 66 | nouveau_mem_del(man, *res); |
| 66 | return ret; | 67 | return ret; |
| 67 | } | 68 | } |
| 68 | 69 | ||
| @@ -118,7 +119,7 @@ nv04_gart_manager_new(struct ttm_resource_manager *man, · 49 unmodified lines | |||
| 118 | ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0, | 119 | ret = nvif_vmm_get(&mem->cli->vmm.vmm, PTES, false, 12, 0, |
| 119 | (long)(*res)->num_pages << PAGE_SHIFT, &mem->vma[0]); | 120 | (long)(*res)->num_pages << PAGE_SHIFT, &mem->vma[0]); |
| 120 | if (ret) { | 121 | if (ret) { |
| 121 | nouveau_mem_del(*res); | 122 | nouveau_mem_del(man, *res); |
| 122 | return ret; | 123 | return ret; |
| 123 | } | 124 | } |
| 124 | 125 | ||
| @@ -163,7 +164,7 @@ nouveau_ttm_init_vram(struct nouveau_drm *drm) · 38 unmodified lines | |||
| 163 | 164 | ||
| 164 | man->func = &nouveau_vram_manager; | 165 | man->func = &nouveau_vram_manager; |
| 165 | 166 | ||
| 166 | ttm_resource_manager_init(man, | 167 | ttm_resource_manager_init(man, &drm->ttm.bdev, |
| 167 | drm->gem.vram_available >> PAGE_SHIFT); | 168 | drm->gem.vram_available >> PAGE_SHIFT); |
| 168 | ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man); | 169 | ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_VRAM, man); |
| 169 | ttm_resource_manager_set_used(man, true); | 170 | ttm_resource_manager_set_used(man, true); |
| @@ -210,7 +211,7 @@ nouveau_ttm_init_gtt(struct nouveau_drm *drm) · 40 unmodified lines | |||
| 210 | 211 | ||
| 211 | man->func = func; | 212 | man->func = func; |
| 212 | man->use_tt = true; | 213 | man->use_tt = true; |
| 213 | ttm_resource_manager_init(man, size_pages); | 214 | ttm_resource_manager_init(man, &drm->ttm.bdev, size_pages); |
| 214 | ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man); | 215 | ttm_set_driver_manager(&drm->ttm.bdev, TTM_PL_TT, man); |
| 215 | ttm_resource_manager_set_used(man, true); | 216 | ttm_resource_manager_set_used(man, true); |
| 216 | return 0; | 217 | return 0; |
| @@ -41,6 +41,10 @@ · 40 unmodified lines | |||
| 41 | 41 | ||
| 42 | struct lt_state { | 42 | struct lt_state { |
| 43 | struct nvkm_dp *dp; | 43 | struct nvkm_dp *dp; |
| 44 | |||
| 45 | int repeaters; | ||
| 46 | int repeater; | ||
| 47 | |||
| 44 | u8 stat[6]; | 48 | u8 stat[6]; |
| 45 | u8 conf[4]; | 49 | u8 conf[4]; |
| 46 | bool pc2; | 50 | bool pc2; |
| @@ -52,14 +56,26 @@ static int · 5 unmodified lines | |||
| 52 | nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) | 56 | nvkm_dp_train_sense(struct lt_state *lt, bool pc, u32 delay) |
| 53 | { | 57 | { |
| 54 | struct nvkm_dp *dp = lt->dp; | 58 | struct nvkm_dp *dp = lt->dp; |
| 59 | u32 addr; | ||
| 55 | int ret; | 60 | int ret; |
| 56 | 61 | ||
| 57 | if (dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL]) | 62 | usleep_range(delay, delay * 2); |
| 58 | mdelay(dp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4); | 63 | |
| 64 | if (lt->repeater) | ||
| 65 | addr = DPCD_LTTPR_LANE0_1_STATUS(lt->repeater); | ||
| 66 | else | ||
| 67 | addr = DPCD_LS02; | ||
| 68 | |||
| 69 | ret = nvkm_rdaux(dp->aux, addr, <->stat[0], 3); | ||
| 70 | if (ret) | ||
| 71 | return ret; | ||
| 72 | |||
| 73 | if (lt->repeater) | ||
| 74 | addr = DPCD_LTTPR_LANE0_1_ADJUST(lt->repeater); | ||
| 59 | else | 75 | else |
| 60 | udelay(delay); | 76 | addr = DPCD_LS06; |
| 61 | 77 | ||
| 62 | ret = nvkm_rdaux(dp->aux, DPCD_LS02, lt->stat, 6); | 78 | ret = nvkm_rdaux(dp->aux, addr, <->stat[4], 2); |
| 63 | if (ret) | 79 | if (ret) |
| 64 | return ret; | 80 | return ret; |
| 65 | 81 | ||
| @@ -85,6 +101,7 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) · 19 unmodified lines | |||
| 85 | struct nvbios_dpout info; | 101 | struct nvbios_dpout info; |
| 86 | struct nvbios_dpcfg ocfg; | 102 | struct nvbios_dpcfg ocfg; |
| 87 | u8 ver, hdr, cnt, len; | 103 | u8 ver, hdr, cnt, len; |
| 104 | u32 addr; | ||
| 88 | u32 data; | 105 | u32 data; |
| 89 | int ret, i; | 106 | int ret, i; |
| 90 | 107 | ||
| @@ -113,6 +130,9 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) · 22 unmodified lines | |||
| 113 | OUTP_TRACE(&dp->outp, "config lane %d %02x %02x", | 130 | OUTP_TRACE(&dp->outp, "config lane %d %02x %02x", |
| 114 | i, lt->conf[i], lpc2); | 131 | i, lt->conf[i], lpc2); |
| 115 | 132 | ||
| 133 | if (lt->repeater != lt->repeaters) | ||
| 134 | continue; | ||
| 135 | |||
| 116 | data = nvbios_dpout_match(bios, dp->outp.info.hasht, | 136 | data = nvbios_dpout_match(bios, dp->outp.info.hasht, |
| 117 | dp->outp.info.hashm, | 137 | dp->outp.info.hashm, |
| 118 | &ver, &hdr, &cnt, &len, &info); | 138 | &ver, &hdr, &cnt, &len, &info); |
| @@ -129,7 +149,12 @@ nvkm_dp_train_drive(struct lt_state *lt, bool pc) · 10 unmodified lines | |||
| 129 | ocfg.pe, ocfg.tx_pu); | 149 | ocfg.pe, ocfg.tx_pu); |
| 130 | } | 150 | } |
| 131 | 151 | ||
| 132 | ret = nvkm_wraux(dp->aux, DPCD_LC03(0), lt->conf, 4); | 152 | if (lt->repeater) |
| 153 | addr = DPCD_LTTPR_LANE0_SET(lt->repeater); | ||
| 154 | else | ||
| 155 | addr = DPCD_LC03(0); | ||
| 156 | |||
| 157 | ret = nvkm_wraux(dp->aux, addr, lt->conf, 4); | ||
| 133 | if (ret) | 158 | if (ret) |
| 134 | return ret; | 159 | return ret; |
| 135 | 160 | ||
| @@ -146,32 +171,59 @@ static void · 10 unmodified lines | |||
| 146 | nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) | 171 | nvkm_dp_train_pattern(struct lt_state *lt, u8 pattern) |
| 147 | { | 172 | { |
| 148 | struct nvkm_dp *dp = lt->dp; | 173 | struct nvkm_dp *dp = lt->dp; |
| 174 | u32 addr; | ||
| 149 | u8 sink_tp; | 175 | u8 sink_tp; |
| 150 | 176 | ||
| 151 | OUTP_TRACE(&dp->outp, "training pattern %d", pattern); | 177 | OUTP_TRACE(&dp->outp, "training pattern %d", pattern); |
| 152 | dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern); | 178 | dp->outp.ior->func->dp.pattern(dp->outp.ior, pattern); |
| 153 | 179 | ||
| 154 | nvkm_rdaux(dp->aux, DPCD_LC02, &sink_tp, 1); | 180 | if (lt->repeater) |
| 181 | addr = DPCD_LTTPR_PATTERN_SET(lt->repeater); | ||
| 182 | else | ||
| 183 | addr = DPCD_LC02; | ||
| 184 | |||
| 185 | nvkm_rdaux(dp->aux, addr, &sink_tp, 1); | ||
| 155 | sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; | 186 | sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; |
| 156 | sink_tp |= pattern; | 187 | sink_tp |= (pattern != 4) ? pattern : 7; |
| 157 | nvkm_wraux(dp->aux, DPCD_LC02, &sink_tp, 1); | 188 | |
| 189 | if (pattern != 0) | ||
| 190 | sink_tp |= DPCD_LC02_SCRAMBLING_DISABLE; | ||
| 191 | else | ||
| 192 | sink_tp &= ~DPCD_LC02_SCRAMBLING_DISABLE; | ||
| 193 | nvkm_wraux(dp->aux, addr, &sink_tp, 1); | ||
| 158 | } | 194 | } |
| 159 | 195 | ||
| 160 | static int | 196 | static int |
| 161 | nvkm_dp_train_eq(struct lt_state *lt) | 197 | nvkm_dp_train_eq(struct lt_state *lt) |
| 162 | { | 198 | { |
| 199 | struct nvkm_i2c_aux *aux = lt->dp->aux; | ||
| 163 | bool eq_done = false, cr_done = true; | 200 | bool eq_done = false, cr_done = true; |
| 164 | int tries = 0, i; | 201 | int tries = 0, usec = 0, i; |
| 202 | u8 data; | ||
| 165 | 203 | ||
| 166 | if (lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) | 204 | if (lt->repeater) { |
| 167 | nvkm_dp_train_pattern(lt, 3); | 205 | if (!nvkm_rdaux(aux, DPCD_LTTPR_AUX_RD_INTERVAL(lt->repeater), &data, sizeof(data))) |
| 168 | else | 206 | usec = (data & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; |
| 169 | nvkm_dp_train_pattern(lt, 2); | 207 | |
| 208 | nvkm_dp_train_pattern(lt, 4); | ||
| 209 | } else { | ||
| 210 | if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x14 && | ||
| 211 | lt->dp->dpcd[DPCD_RC03] & DPCD_RC03_TPS4_SUPPORTED) | ||
| 212 | nvkm_dp_train_pattern(lt, 4); | ||
| 213 | else | ||
| 214 | if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] >= 0x12 && | ||
| 215 | lt->dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED) | ||
| 216 | nvkm_dp_train_pattern(lt, 3); | ||
| 217 | else | ||
| 218 | nvkm_dp_train_pattern(lt, 2); | ||
| 219 | |||
| 220 | usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; | ||
| 221 | } | ||
| 170 | 222 | ||
| 171 | do { | 223 | do { |
| 172 | if ((tries && | 224 | if ((tries && |
| 173 | nvkm_dp_train_drive(lt, lt->pc2)) || | 225 | nvkm_dp_train_drive(lt, lt->pc2)) || |
| 174 | nvkm_dp_train_sense(lt, lt->pc2, 400)) | 226 | nvkm_dp_train_sense(lt, lt->pc2, usec ? usec : 400)) |
| 175 | break; | 227 | break; |
| 176 | 228 | ||
| 177 | eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); | 229 | eq_done = !!(lt->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE); |
| @@ -193,13 +245,16 @@ nvkm_dp_train_cr(struct lt_state *lt) · 15 unmodified lines | |||
| 193 | { | 245 | { |
| 194 | bool cr_done = false, abort = false; | 246 | bool cr_done = false, abort = false; |
| 195 | int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; | 247 | int voltage = lt->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET; |
| 196 | int tries = 0, i; | 248 | int tries = 0, usec = 0, i; |
| 197 | 249 | ||
| 198 | nvkm_dp_train_pattern(lt, 1); | 250 | nvkm_dp_train_pattern(lt, 1); |
| 199 | 251 | ||
| 252 | if (lt->dp->dpcd[DPCD_RC00_DPCD_REV] < 0x14 && !lt->repeater) | ||
| 253 | usec = (lt->dp->dpcd[DPCD_RC0E] & DPCD_RC0E_AUX_RD_INTERVAL) * 4000; | ||
| 254 | |||
| 200 | do { | 255 | do { |
| 201 | if (nvkm_dp_train_drive(lt, false) || | 256 | if (nvkm_dp_train_drive(lt, false) || |
| 202 | nvkm_dp_train_sense(lt, false, 100)) | 257 | nvkm_dp_train_sense(lt, false, usec ? usec : 100)) |
| 203 | break; | 258 | break; |
| 204 | 259 | ||
| 205 | cr_done = true; | 260 | cr_done = true; |
| @@ -223,7 +278,7 @@ nvkm_dp_train_cr(struct lt_state *lt) · 17 unmodified lines | |||
| 223 | } | 278 | } |
| 224 | 279 | ||
| 225 | static int | 280 | static int |
| 226 | nvkm_dp_train_links(struct nvkm_dp *dp) | 281 | nvkm_dp_train_links(struct nvkm_dp *dp, int rate) |
| 227 | { | 282 | { |
| 228 | struct nvkm_ior *ior = dp->outp.ior; | 283 | struct nvkm_ior *ior = dp->outp.ior; |
| 229 | struct nvkm_disp *disp = dp->outp.disp; | 284 | struct nvkm_disp *disp = dp->outp.disp; |
| @@ -233,13 +288,15 @@ nvkm_dp_train_links(struct nvkm_dp *dp) · 3 unmodified lines | |||
| 233 | .dp = dp, | 288 | .dp = dp, |
| 234 | }; | 289 | }; |
| 235 | u32 lnkcmp; | 290 | u32 lnkcmp; |
| 236 | u8 sink[2]; | 291 | u8 sink[2], data; |
| 237 | int ret; | 292 | int ret; |
| 238 | 293 | ||
| 239 | OUTP_DBG(&dp->outp, "training %d x %d MB/s", | 294 | OUTP_DBG(&dp->outp, "training %d x %d MB/s", |
| 240 | ior->dp.nr, ior->dp.bw * 27); | 295 | ior->dp.nr, ior->dp.bw * 27); |
| 241 | 296 | ||
| 242 | /* Intersect misc. capabilities of the OR and sink. */ | 297 | /* Intersect misc. capabilities of the OR and sink. */ |
| 298 | if (disp->engine.subdev.device->chipset < 0x110) | ||
| 299 | dp->dpcd[DPCD_RC03] &= ~DPCD_RC03_TPS4_SUPPORTED; | ||
| 243 | if (disp->engine.subdev.device->chipset < 0xd0) | 300 | if (disp->engine.subdev.device->chipset < 0xd0) |
| 244 | dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; | 301 | dp->dpcd[DPCD_RC02] &= ~DPCD_RC02_TPS3_SUPPORTED; |
| 245 | lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED; | 302 | lt.pc2 = dp->dpcd[DPCD_RC02] & DPCD_RC02_TPS3_SUPPORTED; |
| @@ -287,8 +344,22 @@ nvkm_dp_train_links(struct nvkm_dp *dp) · 41 unmodified lines | |||
| 287 | 344 | ||
| 288 | ior->func->dp.power(ior, ior->dp.nr); | 345 | ior->func->dp.power(ior, ior->dp.nr); |
| 289 | 346 | ||
| 347 | /* Select LTTPR non-transparent mode if we have a valid configuration, | ||
| 348 | * use transparent mode otherwise. | ||
| 349 | */ | ||
| 350 | if (dp->lttpr[0] >= 0x14) { | ||
| 351 | data = DPCD_LTTPR_MODE_TRANSPARENT; | ||
| 352 | nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data)); | ||
| 353 | |||
| 354 | if (dp->lttprs) { | ||
| 355 | data = DPCD_LTTPR_MODE_NON_TRANSPARENT; | ||
| 356 | nvkm_wraux(dp->aux, DPCD_LTTPR_MODE, &data, sizeof(data)); | ||
| 357 | lt.repeaters = dp->lttprs; | ||
| 358 | } | ||
| 359 | } | ||
| 360 | |||
| 290 | /* Set desired link configuration on the sink. */ | 361 | /* Set desired link configuration on the sink. */ |
| 291 | sink[0] = ior->dp.bw; | 362 | sink[0] = (dp->rate[rate].dpcd < 0) ? ior->dp.bw : 0; |
| 292 | sink[1] = ior->dp.nr; | 363 | sink[1] = ior->dp.nr; |
| 293 | if (ior->dp.ef) | 364 | if (ior->dp.ef) |
| 294 | sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; | 365 | sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; |
| @@ -297,12 +368,33 @@ nvkm_dp_train_links(struct nvkm_dp *dp) · 2 unmodified lines | |||
| 297 | if (ret) | 368 | if (ret) |
| 298 | return ret; | 369 | return ret; |
| 299 | 370 | ||
| 371 | if (dp->rate[rate].dpcd >= 0) { | ||
| 372 | ret = nvkm_rdaux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); | ||
| 373 | if (ret) | ||
| 374 | return ret; | ||
| 375 | |||
| 376 | sink[0] &= ~DPCD_LC15_LINK_RATE_SET_MASK; | ||
| 377 | sink[0] |= dp->rate[rate].dpcd; | ||
| 378 | |||
| 379 | ret = nvkm_wraux(dp->aux, DPCD_LC15_LINK_RATE_SET, &sink[0], sizeof(sink[0])); | ||
| 380 | if (ret) | ||
| 381 | return ret; | ||
| 382 | } | ||
| 383 | |||
| 300 | /* Attempt to train the link in this configuration. */ | 384 | /* Attempt to train the link in this configuration. */ |
| 301 | memset(lt.stat, 0x00, sizeof(lt.stat)); | 385 | for (lt.repeater = lt.repeaters; lt.repeater >= 0; lt.repeater--) { |
| 302 | ret = nvkm_dp_train_cr(<); | 386 | if (lt.repeater) |
| 303 | if (ret == 0) | 387 | OUTP_DBG(&dp->outp, "training LTTPR%d", lt.repeater); |
| 304 | ret = nvkm_dp_train_eq(<); | 388 | else |
| 305 | nvkm_dp_train_pattern(<, 0); | 389 | OUTP_DBG(&dp->outp, "training sink"); |
| 390 | |||
| 391 | memset(lt.stat, 0x00, sizeof(lt.stat)); | ||
| 392 | ret = nvkm_dp_train_cr(<); | ||
| 393 | if (ret == 0) | ||
| 394 | ret = nvkm_dp_train_eq(<); | ||
| 395 | nvkm_dp_train_pattern(<, 0); | ||
| 396 | } | ||
| 397 | |||
| 306 | return ret; | 398 | return ret; |
| 307 | } | 399 | } |
| 308 | 400 | ||
| @@ -345,63 +437,13 @@ nvkm_dp_train_init(struct nvkm_dp *dp) · 36 unmodified lines | |||
| 345 | } | 437 | } |
| 346 | } | 438 | } |
| 347 | 439 | ||
| 348 | static const struct dp_rates { | ||
| 349 | u32 rate; | ||
| 350 | u8 bw; | ||
| 351 | u8 nr; | ||
| 352 | } nvkm_dp_rates[] = { | ||
| 353 | { 2160000, 0x14, 4 }, | ||
| 354 | { 1080000, 0x0a, 4 }, | ||
| 355 | { 1080000, 0x14, 2 }, | ||
| 356 | { 648000, 0x06, 4 }, | ||
| 357 | { 540000, 0x0a, 2 }, | ||
| 358 | { 540000, 0x14, 1 }, | ||
| 359 | { 324000, 0x06, 2 }, | ||
| 360 | { 270000, 0x0a, 1 }, | ||
| 361 | { 162000, 0x06, 1 }, | ||
| 362 | {} | ||
| 363 | }; | ||
| 364 | |||
| 365 | static int | 440 | static int |
| 366 | nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) | 441 | nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) |
| 367 | { | 442 | { |
| 368 | struct nvkm_ior *ior = dp->outp.ior; | 443 | struct nvkm_ior *ior = dp->outp.ior; |
| 369 | const u8 sink_nr = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; | 444 | int ret = -EINVAL, nr, rate; |
| 370 | const u8 sink_bw = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; | ||
| 371 | const u8 outp_nr = dp->outp.info.dpconf.link_nr; | ||
| 372 | const u8 outp_bw = dp->outp.info.dpconf.link_bw; | ||
| 373 | const struct dp_rates *failsafe = NULL, *cfg; | ||
| 374 | int ret = -EINVAL; | ||
| 375 | u8 pwr; | 445 | u8 pwr; |
| 376 | 446 | ||
| 377 | /* Find the lowest configuration of the OR that can support | ||
| 378 | * the required link rate. | ||
| 379 | * | ||
| 380 | * We will refuse to program the OR to lower rates, even if | ||
| 381 | * link training fails at higher rates (or even if the sink | ||
| 382 | * can't support the rate at all, though the DD is supposed | ||
| 383 | * to prevent such situations from happening). | ||
| 384 | * | ||
| 385 | * Attempting to do so can cause the entire display to hang, | ||
| 386 | * and it's better to have a failed modeset than that. | ||
| 387 | */ | ||
| 388 | for (cfg = nvkm_dp_rates; cfg->rate; cfg++) { | ||
| 389 | if (cfg->nr <= outp_nr && cfg->bw <= outp_bw) { | ||
| 390 | /* Try to respect sink limits too when selecting | ||
| 391 | * lowest link configuration. | ||
| 392 | */ | ||
| 393 | if (!failsafe || | ||
| 394 | (cfg->nr <= sink_nr && cfg->bw <= sink_bw)) | ||
| 395 | failsafe = cfg; | ||
| 396 | } | ||
| 397 | |||
| 398 | if (failsafe && cfg[1].rate < dataKBps) | ||
| 399 | break; | ||
| 400 | } | ||
| 401 | |||
| 402 | if (WARN_ON(!failsafe)) | ||
| 403 | return ret; | ||
| 404 | |||
| 405 | /* Ensure sink is not in a low-power state. */ | 447 | /* Ensure sink is not in a low-power state. */ |
| 406 | if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { | 448 | if (!nvkm_rdaux(dp->aux, DPCD_SC00, &pwr, 1)) { |
| 407 | if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { | 449 | if ((pwr & DPCD_SC00_SET_POWER) != DPCD_SC00_SET_POWER_D0) { |
| @@ -411,25 +453,22 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 dataKBps) · 3 unmodified lines | |||
| 411 | } | 453 | } |
| 412 | } | 454 | } |
| 413 | 455 | ||
| 456 | ior->dp.mst = dp->lt.mst; | ||
| 457 | ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; | ||
| 458 | ior->dp.nr = 0; | ||
| 459 | |||
| 414 | /* Link training. */ | 460 | /* Link training. */ |
| 415 | OUTP_DBG(&dp->outp, "training (min: %d x %d MB/s)", | 461 | OUTP_DBG(&dp->outp, "training"); |
| 416 | failsafe->nr, failsafe->bw * 27); | ||
| 417 | nvkm_dp_train_init(dp); | 462 | nvkm_dp_train_init(dp); |
| 418 | for (cfg = nvkm_dp_rates; ret < 0 && cfg <= failsafe; cfg++) { | 463 | for (nr = dp->links; ret < 0 && nr; nr >>= 1) { |
| 419 | /* Skip configurations not supported by both OR and sink. */ | 464 | for (rate = 0; ret < 0 && rate < dp->rates; rate++) { |
| 420 | if ((cfg->nr > outp_nr || cfg->bw > outp_bw || | 465 | if (dp->rate[rate].rate * nr >= dataKBps || WARN_ON(!ior->dp.nr)) { |
| 421 | cfg->nr > sink_nr || cfg->bw > sink_bw)) { | 466 | /* Program selected link configuration. */ |
| 422 | if (cfg != failsafe) | 467 | ior->dp.bw = dp->rate[rate].rate / 27000; |
| 423 | continue; | 468 | ior->dp.nr = nr; |
| 424 | OUTP_ERR(&dp->outp, "link rate unsupported by sink"); | 469 | ret = nvkm_dp_train_links(dp, rate); |
| 470 | } | ||
| 425 | } | 471 | } |
| 426 | ior->dp.mst = dp->lt.mst; | ||
| 427 | ior->dp.ef = dp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP; | ||
| 428 | ior->dp.bw = cfg->bw; | ||
| 429 | ior->dp.nr = cfg->nr; | ||
| 430 | |||
| 431 | /* Program selected link configuration. */ | ||
| 432 | ret = nvkm_dp_train_links(dp); | ||
| 433 | } | 472 | } |
| 434 | nvkm_dp_train_fini(dp); | 473 | nvkm_dp_train_fini(dp); |
| 435 | if (ret < 0) | 474 | if (ret < 0) |
| @@ -526,6 +565,47 @@ done: · 90 unmodified lines | |||
| 526 | return ret; | 565 | return ret; |
| 527 | } | 566 | } |
| 528 | 567 | ||
| 568 | static bool | ||
| 569 | nvkm_dp_enable_supported_link_rates(struct nvkm_dp *dp) | ||
| 570 | { | ||
| 571 | u8 sink_rates[DPCD_RC10_SUPPORTED_LINK_RATES__SIZE]; | ||
| 572 | int i, j, k; | ||
| 573 | |||
| 574 | if (dp->outp.conn->info.type != DCB_CONNECTOR_eDP || | ||
| 575 | dp->dpcd[DPCD_RC00_DPCD_REV] < 0x13 || | ||
| 576 | nvkm_rdaux(dp->aux, DPCD_RC10_SUPPORTED_LINK_RATES(0), sink_rates, sizeof(sink_rates))) | ||
| 577 | return false; | ||
| 578 | |||
| 579 | for (i = 0; i < ARRAY_SIZE(sink_rates); i += 2) { | ||
| 580 | const u32 rate = ((sink_rates[i + 1] << 8) | sink_rates[i]) * 200 / 10; | ||
| 581 | |||
| 582 | if (!rate || WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) | ||
| 583 | break; | ||
| 584 | |||
| 585 | if (rate > dp->outp.info.dpconf.link_bw * 27000) { | ||
| 586 | OUTP_DBG(&dp->outp, "rate %d !outp", rate); | ||
| 587 | continue; | ||
| 588 | } | ||
| 589 | |||
| 590 | for (j = 0; j < dp->rates; j++) { | ||
| 591 | if (rate > dp->rate[j].rate) { | ||
| 592 | for (k = dp->rates; k > j; k--) | ||
| 593 | dp->rate[k] = dp->rate[k - 1]; | ||
| 594 | break; | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | dp->rate[j].dpcd = i / 2; | ||
| 599 | dp->rate[j].rate = rate; | ||
| 600 | dp->rates++; | ||
| 601 | } | ||
| 602 | |||
| 603 | for (i = 0; i < dp->rates; i++) | ||
| 604 | OUTP_DBG(&dp->outp, "link_rate[%d] = %d", dp->rate[i].dpcd, dp->rate[i].rate); | ||
| 605 | |||
| 606 | return dp->rates != 0; | ||
| 607 | } | ||
| 608 | |||
| 529 | static bool | 609 | static bool |
| 530 | nvkm_dp_enable(struct nvkm_dp *dp, bool enable) | 610 | nvkm_dp_enable(struct nvkm_dp *dp, bool enable) |
| 531 | { | 611 | { |
| @@ -538,9 +618,60 @@ nvkm_dp_enable(struct nvkm_dp *dp, bool enable) · 6 unmodified lines | |||
| 538 | dp->present = true; | 618 | dp->present = true; |
| 539 | } | 619 | } |
| 540 | 620 | ||
| 541 | if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, | 621 | /* Detect any LTTPRs before reading DPCD receiver caps. */ |
| 542 | sizeof(dp->dpcd))) | 622 | if (!nvkm_rdaux(aux, DPCD_LTTPR_REV, dp->lttpr, sizeof(dp->lttpr)) && |
| 623 | dp->lttpr[0] >= 0x14 && dp->lttpr[2]) { | ||
| 624 | switch (dp->lttpr[2]) { | ||
| 625 | case 0x80: dp->lttprs = 1; break; | ||
| 626 | case 0x40: dp->lttprs = 2; break; | ||
| 627 | case 0x20: dp->lttprs = 3; break; | ||
| 628 | case 0x10: dp->lttprs = 4; break; | ||
| 629 | case 0x08: dp->lttprs = 5; break; | ||
| 630 | case 0x04: dp->lttprs = 6; break; | ||
| 631 | case 0x02: dp->lttprs = 7; break; | ||
| 632 | case 0x01: dp->lttprs = 8; break; | ||
| 633 | default: | ||
| 634 | /* Unknown LTTPR count, we'll switch to transparent mode. */ | ||
| 635 | WARN_ON(1); | ||
| 636 | dp->lttprs = 0; | ||
| 637 | break; | ||
| 638 | } | ||
| 639 | } else { | ||
| 640 | /* No LTTPR support, or zero LTTPR count - don't touch it at all. */ | ||
| 641 | memset(dp->lttpr, 0x00, sizeof(dp->lttpr)); | ||
| 642 | } | ||
| 643 | |||
| 644 | if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, dp->dpcd, sizeof(dp->dpcd))) { | ||
| 645 | const u8 rates[] = { 0x1e, 0x14, 0x0a, 0x06, 0 }; | ||
| 646 | const u8 *rate; | ||
| 647 | int rate_max; | ||
| 648 | |||
| 649 | dp->rates = 0; | ||
| 650 | dp->links = dp->dpcd[DPCD_RC02] & DPCD_RC02_MAX_LANE_COUNT; | ||
| 651 | dp->links = min(dp->links, dp->outp.info.dpconf.link_nr); | ||
| 652 | if (dp->lttprs && dp->lttpr[4]) | ||
| 653 | dp->links = min_t(int, dp->links, dp->lttpr[4]); | ||
| 654 | |||
| 655 | rate_max = dp->dpcd[DPCD_RC01_MAX_LINK_RATE]; | ||
| 656 | rate_max = min(rate_max, dp->outp.info.dpconf.link_bw); | ||
| 657 | if (dp->lttprs && dp->lttpr[1]) | ||
| 658 | rate_max = min_t(int, rate_max, dp->lttpr[1]); | ||
| 659 | |||
| 660 | if (!nvkm_dp_enable_supported_link_rates(dp)) { | ||
| 661 | for (rate = rates; *rate; rate++) { | ||
| 662 | if (*rate <= rate_max) { | ||
| 663 | if (WARN_ON(dp->rates == ARRAY_SIZE(dp->rate))) | ||
| 664 | break; | ||
| 665 | |||
| 666 | dp->rate[dp->rates].dpcd = -1; | ||
| 667 | dp->rate[dp->rates].rate = *rate * 27000; | ||
| 668 | dp->rates++; | ||
| 669 | } | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 543 | return true; | 673 | return true; |
| 674 | } | ||
| 544 | } | 675 | } |
| 545 | 676 | ||
| 546 | if (dp->present) { | 677 | if (dp->present) { |
| @@ -9,10 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <subdev/bios/dp.h> | 9 | #include <subdev/bios/dp.h> |
| 10 | 10 | ||
| 11 | struct nvkm_dp { | 11 | struct nvkm_dp { |
| 12 | union { | 12 | struct nvkm_outp outp; |
| 13 | struct nvkm_outp base; | ||
| 14 | struct nvkm_outp outp; | ||
| 15 | }; | ||
| 16 | 13 | ||
| 17 | struct nvbios_dpout info; | 14 | struct nvbios_dpout info; |
| 18 | u8 version; | 15 | u8 version; |
| @@ -21,8 +18,17 @@ struct nvkm_dp { · 2 unmodified lines | |||
| 21 | 18 | ||
| 22 | struct nvkm_notify hpd; | 19 | struct nvkm_notify hpd; |
| 23 | bool present; | 20 | bool present; |
| 21 | u8 lttpr[6]; | ||
| 22 | u8 lttprs; | ||
| 24 | u8 dpcd[16]; | 23 | u8 dpcd[16]; |
| 25 | 24 | ||
| 25 | struct { | ||
| 26 | int dpcd; /* -1, or index into SUPPORTED_LINK_RATES table */ | ||
| 27 | u32 rate; | ||
| 28 | } rate[8]; | ||
| 29 | int rates; | ||
| 30 | int links; | ||
| 31 | |||
| 26 | struct mutex mutex; | 32 | struct mutex mutex; |
| 27 | struct { | 33 | struct { |
| 28 | atomic_t done; | 34 | atomic_t done; |
| @@ -42,8 +48,12 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 13 unmodified lines | |||
| 42 | #define DPCD_RC02_TPS3_SUPPORTED 0x40 | 48 | #define DPCD_RC02_TPS3_SUPPORTED 0x40 |
| 43 | #define DPCD_RC02_MAX_LANE_COUNT 0x1f | 49 | #define DPCD_RC02_MAX_LANE_COUNT 0x1f |
| 44 | #define DPCD_RC03 0x00003 | 50 | #define DPCD_RC03 0x00003 |
| 51 | #define DPCD_RC03_TPS4_SUPPORTED 0x80 | ||
| 45 | #define DPCD_RC03_MAX_DOWNSPREAD 0x01 | 52 | #define DPCD_RC03_MAX_DOWNSPREAD 0x01 |
| 46 | #define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e | 53 | #define DPCD_RC0E 0x0000e |
| 54 | #define DPCD_RC0E_AUX_RD_INTERVAL 0x7f | ||
| 55 | #define DPCD_RC10_SUPPORTED_LINK_RATES(i) 0x00010 | ||
| 56 | #define DPCD_RC10_SUPPORTED_LINK_RATES__SIZE 16 | ||
| 47 | 57 | ||
| 48 | /* DPCD Link Configuration */ | 58 | /* DPCD Link Configuration */ |
| 49 | #define DPCD_LC00_LINK_BW_SET 0x00100 | 59 | #define DPCD_LC00_LINK_BW_SET 0x00100 |
| @@ -51,7 +61,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 1 unmodified line | |||
| 51 | #define DPCD_LC01_ENHANCED_FRAME_EN 0x80 | 61 | #define DPCD_LC01_ENHANCED_FRAME_EN 0x80 |
| 52 | #define DPCD_LC01_LANE_COUNT_SET 0x1f | 62 | #define DPCD_LC01_LANE_COUNT_SET 0x1f |
| 53 | #define DPCD_LC02 0x00102 | 63 | #define DPCD_LC02 0x00102 |
| 54 | #define DPCD_LC02_TRAINING_PATTERN_SET 0x03 | 64 | #define DPCD_LC02_TRAINING_PATTERN_SET 0x0f |
| 65 | #define DPCD_LC02_SCRAMBLING_DISABLE 0x20 | ||
| 55 | #define DPCD_LC03(l) ((l) + 0x00103) | 66 | #define DPCD_LC03(l) ((l) + 0x00103) |
| 56 | #define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20 | 67 | #define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20 |
| 57 | #define DPCD_LC03_PRE_EMPHASIS_SET 0x18 | 68 | #define DPCD_LC03_PRE_EMPHASIS_SET 0x18 |
| @@ -67,6 +78,8 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 9 unmodified lines | |||
| 67 | #define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30 | 78 | #define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30 |
| 68 | #define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04 | 79 | #define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04 |
| 69 | #define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03 | 80 | #define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03 |
| 81 | #define DPCD_LC15_LINK_RATE_SET 0x00115 | ||
| 82 | #define DPCD_LC15_LINK_RATE_SET_MASK 0x07 | ||
| 70 | 83 | ||
| 71 | /* DPCD Link/Sink Status */ | 84 | /* DPCD Link/Sink Status */ |
| 72 | #define DPCD_LS02 0x00202 | 85 | #define DPCD_LS02 0x00202 |
| @@ -108,4 +121,14 @@ void nvkm_dp_disable(struct nvkm_outp *, struct nvkm_ior *); · 35 unmodified lines | |||
| 108 | #define DPCD_SC00_SET_POWER 0x03 | 121 | #define DPCD_SC00_SET_POWER 0x03 |
| 109 | #define DPCD_SC00_SET_POWER_D0 0x01 | 122 | #define DPCD_SC00_SET_POWER_D0 0x01 |
| 110 | #define DPCD_SC00_SET_POWER_D3 0x03 | 123 | #define DPCD_SC00_SET_POWER_D3 0x03 |
| 124 | |||
| 125 | #define DPCD_LTTPR_REV 0xf0000 | ||
| 126 | #define DPCD_LTTPR_MODE 0xf0003 | ||
| 127 | #define DPCD_LTTPR_MODE_TRANSPARENT 0x55 | ||
| 128 | #define DPCD_LTTPR_MODE_NON_TRANSPARENT 0xaa | ||
| 129 | #define DPCD_LTTPR_PATTERN_SET(i) ((i - 1) * 0x50 + 0xf0010) | ||
| 130 | #define DPCD_LTTPR_LANE0_SET(i) ((i - 1) * 0x50 + 0xf0011) | ||
| 131 | #define DPCD_LTTPR_AUX_RD_INTERVAL(i) ((i - 1) * 0x50 + 0xf0020) | ||
| 132 | #define DPCD_LTTPR_LANE0_1_STATUS(i) ((i - 1) * 0x50 + 0xf0030) | ||
| 133 | #define DPCD_LTTPR_LANE0_1_ADJUST(i) ((i - 1) * 0x50 + 0xf0033) | ||
| 111 | #endif | 134 | #endif |
| @@ -77,7 +77,18 @@ g94_sor_dp_pattern(struct nvkm_ior *sor, int pattern) · 76 unmodified lines | |||
| 77 | { | 77 | { |
| 78 | struct nvkm_device *device = sor->disp->engine.subdev.device; | 78 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 79 | const u32 loff = nv50_sor_link(sor); | 79 | const u32 loff = nv50_sor_link(sor); |
| 80 | nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); | 80 | u32 data; |
| 81 | |||
| 82 | switch (pattern) { | ||
| 83 | case 0: data = 0x00001000; break; | ||
| 84 | case 1: data = 0x01000000; break; | ||
| 85 | case 2: data = 0x02000000; break; | ||
| 86 | default: | ||
| 87 | WARN_ON(1); | ||
| 88 | return; | ||
| 89 | } | ||
| 90 | |||
| 91 | nvkm_mask(device, 0x61c10c + loff, 0x0f001000, data); | ||
| 81 | } | 92 | } |
| 82 | 93 | ||
| 83 | void | 94 | void |
| @@ -37,6 +37,10 @@ ga102_sor_dp_links(struct nvkm_ior *sor, struct nvkm_i2c_aux *aux) · 36 unmodified lines | |||
| 37 | case 0x0a: clksor |= 0x00040000; break; | 37 | case 0x0a: clksor |= 0x00040000; break; |
| 38 | case 0x14: clksor |= 0x00080000; break; | 38 | case 0x14: clksor |= 0x00080000; break; |
| 39 | case 0x1e: clksor |= 0x000c0000; break; | 39 | case 0x1e: clksor |= 0x000c0000; break; |
| 40 | case 0x08: clksor |= 0x00100000; break; | ||
| 41 | case 0x09: clksor |= 0x00140000; break; | ||
| 42 | case 0x0c: clksor |= 0x00180000; break; | ||
| 43 | case 0x10: clksor |= 0x001c0000; break; | ||
| 40 | default: | 44 | default: |
| 41 | WARN_ON(1); | 45 | WARN_ON(1); |
| 42 | return -EINVAL; | 46 | return -EINVAL; |
| @@ -92,7 +92,19 @@ gf119_sor_dp_pattern(struct nvkm_ior *sor, int pattern) · 91 unmodified lines | |||
| 92 | { | 92 | { |
| 93 | struct nvkm_device *device = sor->disp->engine.subdev.device; | 93 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 94 | const u32 soff = nv50_ior_base(sor); | 94 | const u32 soff = nv50_ior_base(sor); |
| 95 | nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, 0x01010101 * pattern); | 95 | u32 data; |
| 96 | |||
| 97 | switch (pattern) { | ||
| 98 | case 0: data = 0x10101010; break; | ||
| 99 | case 1: data = 0x01010101; break; | ||
| 100 | case 2: data = 0x02020202; break; | ||
| 101 | case 3: data = 0x03030303; break; | ||
| 102 | default: | ||
| 103 | WARN_ON(1); | ||
| 104 | return; | ||
| 105 | } | ||
| 106 | |||
| 107 | nvkm_mask(device, 0x61c110 + soff, 0x1f1f1f1f, data); | ||
| 96 | } | 108 | } |
| 97 | 109 | ||
| 98 | int | 110 | int |
| @@ -28,11 +28,23 @@ gm107_sor_dp_pattern(struct nvkm_ior *sor, int pattern) · 27 unmodified lines | |||
| 28 | { | 28 | { |
| 29 | struct nvkm_device *device = sor->disp->engine.subdev.device; | 29 | struct nvkm_device *device = sor->disp->engine.subdev.device; |
| 30 | const u32 soff = nv50_ior_base(sor); | 30 | const u32 soff = nv50_ior_base(sor); |
| 31 | const u32 data = 0x01010101 * pattern; | 31 | u32 mask = 0x1f1f1f1f, data; |
| 32 | |||
| 33 | switch (pattern) { | ||
| 34 | case 0: data = 0x10101010; break; | ||
| 35 | case 1: data = 0x01010101; break; | ||
| 36 | case 2: data = 0x02020202; break; | ||
| 37 | case 3: data = 0x03030303; break; | ||
| 38 | case 4: data = 0x1b1b1b1b; break; | ||
| 39 | default: | ||
| 40 | WARN_ON(1); | ||
| 41 | return; | ||
| 42 | } | ||
| 43 | |||
| 32 | if (sor->asy.link & 1) | 44 | if (sor->asy.link & 1) |
| 33 | nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); | 45 | nvkm_mask(device, 0x61c110 + soff, mask, data); |
| 34 | else | 46 | else |
| 35 | nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); | 47 | nvkm_mask(device, 0x61c12c + soff, mask, data); |
| 36 | } | 48 | } |
| 37 | 49 | ||
| 38 | static const struct nvkm_ior_func | 50 | static const struct nvkm_ior_func |
| @@ -142,11 +142,12 @@ nvkm_acr_hsfw_load_bl(struct nvkm_acr *acr, const char *name, int ver, · 141 unmodified lines | |||
| 142 | 142 | ||
| 143 | hsfw->imem_size = desc->code_size; | 143 | hsfw->imem_size = desc->code_size; |
| 144 | hsfw->imem_tag = desc->start_tag; | 144 | hsfw->imem_tag = desc->start_tag; |
| 145 | hsfw->imem = kmalloc(desc->code_size, GFP_KERNEL); | 145 | hsfw->imem = kmemdup(data + desc->code_off, desc->code_size, GFP_KERNEL); |
| 146 | memcpy(hsfw->imem, data + desc->code_off, desc->code_size); | ||
| 147 | |||
| 148 | nvkm_firmware_put(fw); | 146 | nvkm_firmware_put(fw); |
| 149 | return 0; | 147 | if (!hsfw->imem) |
| 148 | return -ENOMEM; | ||
| 149 | else | ||
| 150 | return 0; | ||
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | int | 153 | int |
| @@ -93,6 +93,7 @@ struct dma_buf *omap_gem_prime_export(struct drm_gem_object *obj, int flags) · 92 unmodified lines | |||
| 93 | exp_info.size = omap_gem_mmap_size(obj); | 93 | exp_info.size = omap_gem_mmap_size(obj); |
| 94 | exp_info.flags = flags; | 94 | exp_info.flags = flags; |
| 95 | exp_info.priv = obj; | 95 | exp_info.priv = obj; |
| 96 | exp_info.resv = obj->resv; | ||
| 96 | 97 | ||
| 97 | return drm_gem_dmabuf_export(obj->dev, &exp_info); | 98 | return drm_gem_dmabuf_export(obj->dev, &exp_info); |
| 98 | } | 99 | } |
| @@ -86,7 +86,7 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = { · 85 unmodified lines | |||
| 86 | _INIT_DCS_CMD(0x0F, 0x73), | 86 | _INIT_DCS_CMD(0x0F, 0x73), |
| 87 | _INIT_DCS_CMD(0x95, 0xE6), | 87 | _INIT_DCS_CMD(0x95, 0xE6), |
| 88 | _INIT_DCS_CMD(0x96, 0xF0), | 88 | _INIT_DCS_CMD(0x96, 0xF0), |
| 89 | _INIT_DCS_CMD(0x30, 0x11), | 89 | _INIT_DCS_CMD(0x30, 0x00), |
| 90 | _INIT_DCS_CMD(0x6D, 0x66), | 90 | _INIT_DCS_CMD(0x6D, 0x66), |
| 91 | _INIT_DCS_CMD(0x75, 0xA2), | 91 | _INIT_DCS_CMD(0x75, 0xA2), |
| 92 | _INIT_DCS_CMD(0x77, 0x3B), | 92 | _INIT_DCS_CMD(0x77, 0x3B), |
| @@ -112,17 +112,17 @@ static const struct panel_init_cmd boe_tv110c9m_init_cmd[] = { · 19 unmodified lines | |||
| 112 | _INIT_DCS_CMD(0xB1, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), | 112 | _INIT_DCS_CMD(0xB1, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), |
| 113 | _INIT_DCS_CMD(0xB2, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), | 113 | _INIT_DCS_CMD(0xB2, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), |
| 114 | 114 | ||
| 115 | _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), | 115 | _INIT_DCS_CMD(0xB3, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), |
| 116 | _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), | 116 | _INIT_DCS_CMD(0xB4, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), |
| 117 | _INIT_DCS_CMD(0xB5, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), | 117 | _INIT_DCS_CMD(0xB5, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), |
| 118 | _INIT_DCS_CMD(0xB6, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), | 118 | _INIT_DCS_CMD(0xB6, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), |
| 119 | _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), | 119 | _INIT_DCS_CMD(0xB7, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), |
| 120 | 120 | ||
| 121 | _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), | 121 | _INIT_DCS_CMD(0xB8, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x45, 0x00, 0x65, 0x00, 0x81, 0x00, 0x99, 0x00, 0xAE, 0x00, 0xC1), |
| 122 | _INIT_DCS_CMD(0xB9, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), | 122 | _INIT_DCS_CMD(0xB9, 0x00, 0xD2, 0x01, 0x0B, 0x01, 0x34, 0x01, 0x76, 0x01, 0xA3, 0x01, 0xEF, 0x02, 0x27, 0x02, 0x29), |
| 123 | _INIT_DCS_CMD(0xBA, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), | 123 | _INIT_DCS_CMD(0xBA, 0x02, 0x5F, 0x02, 0x9E, 0x02, 0xC9, 0x03, 0x00, 0x03, 0x26, 0x03, 0x53, 0x03, 0x63, 0x03, 0x73), |
| 124 | 124 | ||
| 125 | _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xA7, 0x03, 0xCF, 0x03, 0xDE, 0x03, 0xE0), | 125 | _INIT_DCS_CMD(0xBB, 0x03, 0x86, 0x03, 0x9A, 0x03, 0xAF, 0x03, 0xDF, 0x03, 0xF5, 0x03, 0xE0), |
| 126 | _INIT_DCS_CMD(0xFF, 0x24), | 126 | _INIT_DCS_CMD(0xFF, 0x24), |
| 127 | _INIT_DCS_CMD(0xFB, 0x01), | 127 | _INIT_DCS_CMD(0xFB, 0x01), |
| 128 | 128 | ||
| @@ -36,8 +36,8 @@ · 35 unmodified lines | |||
| 36 | 36 | ||
| 37 | #include <drm/drm_crtc.h> | 37 | #include <drm/drm_crtc.h> |
| 38 | #include <drm/drm_device.h> | 38 | #include <drm/drm_device.h> |
| 39 | #include <drm/drm_dp_aux_bus.h> | 39 | #include <drm/dp/drm_dp_aux_bus.h> |
| 40 | #include <drm/drm_dp_helper.h> | 40 | #include <drm/dp/drm_dp_helper.h> |
| 41 | #include <drm/drm_panel.h> | 41 | #include <drm/drm_panel.h> |
| 42 | 42 | ||
| 43 | /** | 43 | /** |
| @@ -1745,6 +1745,19 @@ static const struct panel_delay delay_200_500_e50 = { · 1701 unmodified lines | |||
| 1745 | .enable = 50, | 1745 | .enable = 50, |
| 1746 | }; | 1746 | }; |
| 1747 | 1747 | ||
| 1748 | static const struct panel_delay delay_200_500_e80_d50 = { | ||
| 1749 | .hpd_absent = 200, | ||
| 1750 | .unprepare = 500, | ||
| 1751 | .enable = 80, | ||
| 1752 | .disable = 50, | ||
| 1753 | }; | ||
| 1754 | |||
| 1755 | static const struct panel_delay delay_100_500_e200 = { | ||
| 1756 | .hpd_absent = 100, | ||
| 1757 | .unprepare = 500, | ||
| 1758 | .enable = 200, | ||
| 1759 | }; | ||
| 1760 | |||
| 1748 | #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ | 1761 | #define EDP_PANEL_ENTRY(vend_chr_0, vend_chr_1, vend_chr_2, product_id, _delay, _name) \ |
| 1749 | { \ | 1762 | { \ |
| 1750 | .name = _name, \ | 1763 | .name = _name, \ |
| @@ -1768,13 +1781,17 @@ static const struct edp_panel_entry edp_panels[] = { · 17 unmodified lines | |||
| 1768 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), | 1781 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x07d1, &boe_nv133fhm_n61.delay, "NV133FHM-N61"), |
| 1769 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), | 1782 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x082d, &boe_nv133fhm_n61.delay, "NV133FHM-N62"), |
| 1770 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), | 1783 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x098d, &boe_nv110wtm_n61.delay, "NV110WTM-N61"), |
| 1784 | EDP_PANEL_ENTRY('B', 'O', 'E', 0x0a5d, &delay_200_500_e50, "NV116WHM-N45"), | ||
| 1771 | 1785 | ||
| 1772 | EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), | 1786 | EDP_PANEL_ENTRY('C', 'M', 'N', 0x114c, &innolux_n116bca_ea1.delay, "N116BCA-EA1"), |
| 1773 | 1787 | ||
| 1774 | EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), | 1788 | EDP_PANEL_ENTRY('K', 'D', 'B', 0x0624, &kingdisplay_kd116n21_30nv_a010.delay, "116N21-30NV-A010"), |
| 1789 | EDP_PANEL_ENTRY('K', 'D', 'B', 0x1120, &delay_200_500_e80_d50, "116N29-30NK-C007"), | ||
| 1775 | 1790 | ||
| 1776 | EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), | 1791 | EDP_PANEL_ENTRY('S', 'H', 'P', 0x154c, &delay_200_500_p2e100, "LQ116M1JW10"), |
| 1777 | 1792 | ||
| 1793 | EDP_PANEL_ENTRY('S', 'T', 'A', 0x0100, &delay_100_500_e200, "2081116HHD028001-51D"), | ||
| 1794 | |||
| 1778 | { /* sentinal */ } | 1795 | { /* sentinal */ } |
| 1779 | }; | 1796 | }; |
| 1780 | 1797 | ||
| @@ -14,8 +14,8 @@ · 13 unmodified lines | |||
| 14 | #include <linux/pm_runtime.h> | 14 | #include <linux/pm_runtime.h> |
| 15 | #include <linux/regulator/consumer.h> | 15 | #include <linux/regulator/consumer.h> |
| 16 | 16 | ||
| 17 | #include <drm/drm_dp_aux_bus.h> | 17 | #include <drm/dp/drm_dp_aux_bus.h> |
| 18 | #include <drm/drm_dp_helper.h> | 18 | #include <drm/dp/drm_dp_helper.h> |
| 19 | #include <drm/drm_edid.h> | 19 | #include <drm/drm_edid.h> |
| 20 | #include <drm/drm_panel.h> | 20 | #include <drm/drm_panel.h> |
| 21 | 21 | ||
| @@ -2525,6 +2525,36 @@ static const struct panel_desc mitsubishi_aa070mc01 = { · 2524 unmodified lines | |||
| 2525 | .bus_flags = DRM_BUS_FLAG_DE_HIGH, | 2525 | .bus_flags = DRM_BUS_FLAG_DE_HIGH, |
| 2526 | }; | 2526 | }; |
| 2527 | 2527 | ||
| 2528 | static const struct display_timing multi_inno_mi0700s4t_6_timing = { | ||
| 2529 | .pixelclock = { 29000000, 33000000, 38000000 }, | ||
| 2530 | .hactive = { 800, 800, 800 }, | ||
| 2531 | .hfront_porch = { 180, 210, 240 }, | ||
| 2532 | .hback_porch = { 16, 16, 16 }, | ||
| 2533 | .hsync_len = { 30, 30, 30 }, | ||
| 2534 | .vactive = { 480, 480, 480 }, | ||
| 2535 | .vfront_porch = { 12, 22, 32 }, | ||
| 2536 | .vback_porch = { 10, 10, 10 }, | ||
| 2537 | .vsync_len = { 13, 13, 13 }, | ||
| 2538 | .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW | | ||
| 2539 | DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_PIXDATA_POSEDGE | | ||
| 2540 | DISPLAY_FLAGS_SYNC_POSEDGE, | ||
| 2541 | }; | ||
| 2542 | |||
| 2543 | static const struct panel_desc multi_inno_mi0700s4t_6 = { | ||
| 2544 | .timings = &multi_inno_mi0700s4t_6_timing, | ||
| 2545 | .num_timings = 1, | ||
| 2546 | .bpc = 8, | ||
| 2547 | .size = { | ||
| 2548 | .width = 154, | ||
| 2549 | .height = 86, | ||
| 2550 | }, | ||
| 2551 | .bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||
| 2552 | .bus_flags = DRM_BUS_FLAG_DE_HIGH | | ||
| 2553 | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE | | ||
| 2554 | DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE, | ||
| 2555 | .connector_type = DRM_MODE_CONNECTOR_DPI, | ||
| 2556 | }; | ||
| 2557 | |||
| 2528 | static const struct display_timing multi_inno_mi1010ait_1cp_timing = { | 2558 | static const struct display_timing multi_inno_mi1010ait_1cp_timing = { |
| 2529 | .pixelclock = { 68900000, 70000000, 73400000 }, | 2559 | .pixelclock = { 68900000, 70000000, 73400000 }, |
| 2530 | .hactive = { 1280, 1280, 1280 }, | 2560 | .hactive = { 1280, 1280, 1280 }, |
| @@ -3871,6 +3901,9 @@ static const struct of_device_id platform_of_match[] = { · 1340 unmodified lines | |||
| 3871 | }, { | 3901 | }, { |
| 3872 | .compatible = "mitsubishi,aa070mc01-ca1", | 3902 | .compatible = "mitsubishi,aa070mc01-ca1", |
| 3873 | .data = &mitsubishi_aa070mc01, | 3903 | .data = &mitsubishi_aa070mc01, |
| 3904 | }, { | ||
| 3905 | .compatible = "multi-inno,mi0700s4t-6", | ||
| 3906 | .data = &multi_inno_mi0700s4t_6, | ||
| 3874 | }, { | 3907 | }, { |
| 3875 | .compatible = "multi-inno,mi1010ait-1cp", | 3908 | .compatible = "multi-inno,mi1010ait-1cp", |
| 3876 | .data = &multi_inno_mi1010ait_1cp, | 3909 | .data = &multi_inno_mi1010ait_1cp, |
| @@ -12,24 +12,6 @@ enum panfrost_hw_feature { · 11 unmodified lines | |||
| 12 | HW_FEATURE_JOBCHAIN_DISAMBIGUATION, | 12 | HW_FEATURE_JOBCHAIN_DISAMBIGUATION, |
| 13 | HW_FEATURE_PWRON_DURING_PWROFF_TRANS, | 13 | HW_FEATURE_PWRON_DURING_PWROFF_TRANS, |
| 14 | HW_FEATURE_XAFFINITY, | 14 | HW_FEATURE_XAFFINITY, |
| 15 | HW_FEATURE_OUT_OF_ORDER_EXEC, | ||
| 16 | HW_FEATURE_MRT, | ||
| 17 | HW_FEATURE_BRNDOUT_CC, | ||
| 18 | HW_FEATURE_INTERPIPE_REG_ALIASING, | ||
| 19 | HW_FEATURE_LD_ST_TILEBUFFER, | ||
| 20 | HW_FEATURE_MSAA_16X, | ||
| 21 | HW_FEATURE_32_BIT_UNIFORM_ADDRESS, | ||
| 22 | HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL, | ||
| 23 | HW_FEATURE_OPTIMIZED_COVERAGE_MASK, | ||
| 24 | HW_FEATURE_T7XX_PAIRING_RULES, | ||
| 25 | HW_FEATURE_LD_ST_LEA_TEX, | ||
| 26 | HW_FEATURE_LINEAR_FILTER_FLOAT, | ||
| 27 | HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4, | ||
| 28 | HW_FEATURE_IMAGES_IN_FRAGMENT_SHADERS, | ||
| 29 | HW_FEATURE_TEST4_DATUM_MODE, | ||
| 30 | HW_FEATURE_NEXT_INSTRUCTION_TYPE, | ||
| 31 | HW_FEATURE_BRNDOUT_KILL, | ||
| 32 | HW_FEATURE_WARPING, | ||
| 33 | HW_FEATURE_V4, | 15 | HW_FEATURE_V4, |
| 34 | HW_FEATURE_FLUSH_REDUCTION, | 16 | HW_FEATURE_FLUSH_REDUCTION, |
| 35 | HW_FEATURE_PROTECTED_MODE, | 17 | HW_FEATURE_PROTECTED_MODE, |
| @@ -42,128 +24,31 @@ enum panfrost_hw_feature { · 6 unmodified lines | |||
| 42 | }; | 24 | }; |
| 43 | 25 | ||
| 44 | #define hw_features_t600 (\ | 26 | #define hw_features_t600 (\ |
| 45 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 46 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 47 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | 27 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 48 | BIT_ULL(HW_FEATURE_V4)) | 28 | BIT_ULL(HW_FEATURE_V4)) |
| 49 | 29 | ||
| 50 | #define hw_features_t620 (\ | 30 | #define hw_features_t620 hw_features_t600 |
| 51 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 52 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 53 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 54 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | ||
| 55 | BIT_ULL(HW_FEATURE_V4)) | ||
| 56 | |||
| 57 | #define hw_features_t720 (\ | ||
| 58 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 59 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 60 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 61 | BIT_ULL(HW_FEATURE_OPTIMIZED_COVERAGE_MASK) | \ | ||
| 62 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 63 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | ||
| 64 | BIT_ULL(HW_FEATURE_WORKGROUP_ROUND_MULTIPLE_OF_4) | \ | ||
| 65 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 66 | BIT_ULL(HW_FEATURE_V4)) | ||
| 67 | 31 | ||
| 32 | #define hw_features_t720 hw_features_t600 | ||
| 68 | 33 | ||
| 69 | #define hw_features_t760 (\ | 34 | #define hw_features_t760 (\ |
| 70 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | 35 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 71 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | 36 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 72 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | 37 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 73 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 74 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 75 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 76 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 77 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 78 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 79 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 80 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 81 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 82 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 83 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 84 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | 38 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) |
| 85 | 39 | ||
| 86 | // T860 | 40 | #define hw_features_t860 hw_features_t760 |
| 87 | #define hw_features_t860 (\ | ||
| 88 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | ||
| 89 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | ||
| 90 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | ||
| 91 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 92 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 93 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 94 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 95 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 96 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 97 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 98 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 99 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 100 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 101 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 102 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 103 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 104 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | ||
| 105 | 41 | ||
| 106 | #define hw_features_t880 hw_features_t860 | 42 | #define hw_features_t880 hw_features_t760 |
| 107 | 43 | ||
| 108 | #define hw_features_t830 (\ | 44 | #define hw_features_t830 hw_features_t760 |
| 109 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | ||
| 110 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | ||
| 111 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | ||
| 112 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 113 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 114 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 115 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 116 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 117 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 118 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 119 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 120 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 121 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 122 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 123 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 124 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 125 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 126 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | ||
| 127 | 45 | ||
| 128 | #define hw_features_t820 (\ | 46 | #define hw_features_t820 hw_features_t760 |
| 129 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | ||
| 130 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | ||
| 131 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | ||
| 132 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 133 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 134 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 135 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 136 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 137 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 138 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 139 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 140 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 141 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 142 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 143 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 144 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 145 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 146 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT)) | ||
| 147 | 47 | ||
| 148 | #define hw_features_g71 (\ | 48 | #define hw_features_g71 (\ |
| 149 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | 49 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 150 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | 50 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 151 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | 51 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 152 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 153 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 154 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 155 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 156 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 157 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 158 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 159 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 160 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 161 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 162 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 163 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 164 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 165 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 166 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 167 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | 52 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 168 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | 53 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 169 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | 54 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -173,71 +58,18 @@ enum panfrost_hw_feature { · 3 unmodified lines | |||
| 173 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | 58 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 174 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | 59 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 175 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | 60 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 176 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 177 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 178 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 179 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 180 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 181 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 182 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 183 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 184 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 185 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 186 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 187 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 188 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 189 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 190 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 191 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | 61 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 192 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | 62 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 193 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | 63 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| 194 | BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ | 64 | BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ |
| 195 | BIT_ULL(HW_FEATURE_COHERENCY_REG)) | 65 | BIT_ULL(HW_FEATURE_COHERENCY_REG)) |
| 196 | 66 | ||
| 197 | #define hw_features_g51 (\ | 67 | #define hw_features_g51 hw_features_g72 |
| 198 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | ||
| 199 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | ||
| 200 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | ||
| 201 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 202 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 203 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 204 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 205 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 206 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 207 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 208 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 209 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 210 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 211 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 212 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 213 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 214 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 215 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 216 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | ||
| 217 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | ||
| 218 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | ||
| 219 | BIT_ULL(HW_FEATURE_PROTECTED_DEBUG_MODE) | \ | ||
| 220 | BIT_ULL(HW_FEATURE_COHERENCY_REG)) | ||
| 221 | 68 | ||
| 222 | #define hw_features_g52 (\ | 69 | #define hw_features_g52 (\ |
| 223 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | 70 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 224 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | 71 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 225 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | 72 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 226 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 227 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 228 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 229 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 230 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 231 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 232 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 233 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 234 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 235 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 236 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 237 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 238 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 239 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 240 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 241 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | 73 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 242 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | 74 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 243 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | 75 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -248,21 +80,6 @@ enum panfrost_hw_feature { · 4 unmodified lines | |||
| 248 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | 80 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 249 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | 81 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 250 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | 82 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 251 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 252 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 253 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 254 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 255 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 256 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 257 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 258 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 259 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 260 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 261 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 262 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 263 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 264 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 265 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 266 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | 83 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 267 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | 84 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 268 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | 85 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -276,21 +93,6 @@ enum panfrost_hw_feature { · 7 unmodified lines | |||
| 276 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ | 93 | BIT_ULL(HW_FEATURE_JOBCHAIN_DISAMBIGUATION) | \ |
| 277 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ | 94 | BIT_ULL(HW_FEATURE_PWRON_DURING_PWROFF_TRANS) | \ |
| 278 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ | 95 | BIT_ULL(HW_FEATURE_XAFFINITY) | \ |
| 279 | BIT_ULL(HW_FEATURE_WARPING) | \ | ||
| 280 | BIT_ULL(HW_FEATURE_INTERPIPE_REG_ALIASING) | \ | ||
| 281 | BIT_ULL(HW_FEATURE_32_BIT_UNIFORM_ADDRESS) | \ | ||
| 282 | BIT_ULL(HW_FEATURE_ATTR_AUTO_TYPE_INFERRAL) | \ | ||
| 283 | BIT_ULL(HW_FEATURE_BRNDOUT_CC) | \ | ||
| 284 | BIT_ULL(HW_FEATURE_BRNDOUT_KILL) | \ | ||
| 285 | BIT_ULL(HW_FEATURE_LD_ST_LEA_TEX) | \ | ||
| 286 | BIT_ULL(HW_FEATURE_LD_ST_TILEBUFFER) | \ | ||
| 287 | BIT_ULL(HW_FEATURE_LINEAR_FILTER_FLOAT) | \ | ||
| 288 | BIT_ULL(HW_FEATURE_MRT) | \ | ||
| 289 | BIT_ULL(HW_FEATURE_MSAA_16X) | \ | ||
| 290 | BIT_ULL(HW_FEATURE_NEXT_INSTRUCTION_TYPE) | \ | ||
| 291 | BIT_ULL(HW_FEATURE_OUT_OF_ORDER_EXEC) | \ | ||
| 292 | BIT_ULL(HW_FEATURE_T7XX_PAIRING_RULES) | \ | ||
| 293 | BIT_ULL(HW_FEATURE_TEST4_DATUM_MODE) | \ | ||
| 294 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ | 96 | BIT_ULL(HW_FEATURE_THREAD_GROUP_SPLIT) | \ |
| 295 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ | 97 | BIT_ULL(HW_FEATURE_FLUSH_REDUCTION) | \ |
| 296 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ | 98 | BIT_ULL(HW_FEATURE_PROTECTED_MODE) | \ |
| @@ -320,19 +320,36 @@ void panfrost_gpu_power_on(struct panfrost_device *pfdev) · 319 unmodified lines | |||
| 320 | { | 320 | { |
| 321 | int ret; | 321 | int ret; |
| 322 | u32 val; | 322 | u32 val; |
| 323 | u64 core_mask = U64_MAX; | ||
| 323 | 324 | ||
| 324 | panfrost_gpu_init_quirks(pfdev); | 325 | panfrost_gpu_init_quirks(pfdev); |
| 325 | 326 | ||
| 326 | /* Just turn on everything for now */ | 327 | if (pfdev->features.l2_present != 1) { |
| 327 | gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present); | 328 | /* |
| 329 | * Only support one core group now. | ||
| 330 | * ~(l2_present - 1) unsets all bits in l2_present except | ||
| 331 | * the bottom bit. (l2_present - 2) has all the bits in | ||
| 332 | * the first core group set. AND them together to generate | ||
| 333 | * a mask of cores in the first core group. | ||
| 334 | */ | ||
| 335 | core_mask = ~(pfdev->features.l2_present - 1) & | ||
| 336 | (pfdev->features.l2_present - 2); | ||
| 337 | dev_info_once(pfdev->dev, "using only 1st core group (%lu cores from %lu)\n", | ||
| 338 | hweight64(core_mask), | ||
| 339 | hweight64(pfdev->features.shader_present)); | ||
| 340 | } | ||
| 341 | gpu_write(pfdev, L2_PWRON_LO, pfdev->features.l2_present & core_mask); | ||
| 328 | ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, | 342 | ret = readl_relaxed_poll_timeout(pfdev->iomem + L2_READY_LO, |
| 329 | val, val == pfdev->features.l2_present, 100, 20000); | 343 | val, val == (pfdev->features.l2_present & core_mask), |
| 344 | 100, 20000); | ||
| 330 | if (ret) | 345 | if (ret) |
| 331 | dev_err(pfdev->dev, "error powering up gpu L2"); | 346 | dev_err(pfdev->dev, "error powering up gpu L2"); |
| 332 | 347 | ||
| 333 | gpu_write(pfdev, SHADER_PWRON_LO, pfdev->features.shader_present); | 348 | gpu_write(pfdev, SHADER_PWRON_LO, |
| 349 | pfdev->features.shader_present & core_mask); | ||
| 334 | ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, | 350 | ret = readl_relaxed_poll_timeout(pfdev->iomem + SHADER_READY_LO, |
| 335 | val, val == pfdev->features.shader_present, 100, 20000); | 351 | val, val == (pfdev->features.shader_present & core_mask), |
| 352 | 100, 20000); | ||
| 336 | if (ret) | 353 | if (ret) |
| 337 | dev_err(pfdev->dev, "error powering up gpu shader"); | 354 | dev_err(pfdev->dev, "error powering up gpu shader"); |
| 338 | 355 | ||
| @@ -360,8 +377,11 @@ int panfrost_gpu_init(struct panfrost_device *pfdev) · 21 unmodified lines | |||
| 360 | 377 | ||
| 361 | panfrost_gpu_init_features(pfdev); | 378 | panfrost_gpu_init_features(pfdev); |
| 362 | 379 | ||
| 363 | dma_set_mask_and_coherent(pfdev->dev, | 380 | err = dma_set_mask_and_coherent(pfdev->dev, |
| 364 | DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); | 381 | DMA_BIT_MASK(FIELD_GET(0xff00, pfdev->features.mmu_features))); |
| 382 | if (err) | ||
| 383 | return err; | ||
| 384 | |||
| 365 | dma_set_max_seg_size(pfdev->dev, UINT_MAX); | 385 | dma_set_max_seg_size(pfdev->dev, UINT_MAX); |
| 366 | 386 | ||
| 367 | irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); | 387 | irq = platform_get_irq_byname(to_platform_device(pfdev->dev), "gpu"); |
| @@ -30,7 +30,7 @@ · 29 unmodified lines | |||
| 30 | 30 | ||
| 31 | #include "atom.h" | 31 | #include "atom.h" |
| 32 | #include "atom-bits.h" | 32 | #include "atom-bits.h" |
| 33 | #include <drm/drm_dp_helper.h> | 33 | #include <drm/dp/drm_dp_helper.h> |
| 34 | 34 | ||
| 35 | /* move these to drm_dp_helper.c/h */ | 35 | /* move these to drm_dp_helper.c/h */ |
| 36 | #define DP_LINK_CONFIGURATION_SIZE 9 | 36 | #define DP_LINK_CONFIGURATION_SIZE 9 |
| @@ -27,7 +27,7 @@ · 26 unmodified lines | |||
| 27 | #include <drm/drm_edid.h> | 27 | #include <drm/drm_edid.h> |
| 28 | #include <drm/drm_crtc_helper.h> | 28 | #include <drm/drm_crtc_helper.h> |
| 29 | #include <drm/drm_fb_helper.h> | 29 | #include <drm/drm_fb_helper.h> |
| 30 | #include <drm/drm_dp_mst_helper.h> | 30 | #include <drm/dp/drm_dp_mst_helper.h> |
| 31 | #include <drm/drm_probe_helper.h> | 31 | #include <drm/drm_probe_helper.h> |
| 32 | #include <drm/radeon_drm.h> | 32 | #include <drm/radeon_drm.h> |
| 33 | #include "radeon.h" | 33 | #include "radeon.h" |
| @@ -204,7 +204,7 @@ int radeon_get_monitor_bpc(struct drm_connector *connector) · 170 unmodified lines | |||
| 204 | 204 | ||
| 205 | /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ | 205 | /* Check if bpc is within clock limit. Try to degrade gracefully otherwise */ |
| 206 | if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { | 206 | if ((bpc == 12) && (mode_clock * 3/2 > max_tmds_clock)) { |
| 207 | if ((connector->display_info.edid_hdmi_dc_modes & DRM_EDID_HDMI_DC_30) && | 207 | if ((connector->display_info.edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30) && |
| 208 | (mode_clock * 5/4 <= max_tmds_clock)) | 208 | (mode_clock * 5/4 <= max_tmds_clock)) |
| 209 | bpc = 10; | 209 | bpc = 10; |
| 210 | else | 210 | else |
| @@ -1,6 +1,6 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | 1 | // SPDX-License-Identifier: MIT |
| 2 | 2 | ||
| 3 | #include <drm/drm_dp_mst_helper.h> | 3 | #include <drm/dp/drm_dp_mst_helper.h> |
| 4 | #include <drm/drm_fb_helper.h> | 4 | #include <drm/drm_fb_helper.h> |
| 5 | #include <drm/drm_file.h> | 5 | #include <drm/drm_file.h> |
| 6 | #include <drm/drm_probe_helper.h> | 6 | #include <drm/drm_probe_helper.h> |
| @@ -33,8 +33,8 @@ · 32 unmodified lines | |||
| 33 | #include <drm/drm_crtc.h> | 33 | #include <drm/drm_crtc.h> |
| 34 | #include <drm/drm_edid.h> | 34 | #include <drm/drm_edid.h> |
| 35 | #include <drm/drm_encoder.h> | 35 | #include <drm/drm_encoder.h> |
| 36 | #include <drm/drm_dp_helper.h> | 36 | #include <drm/dp/drm_dp_helper.h> |
| 37 | #include <drm/drm_dp_mst_helper.h> | 37 | #include <drm/dp/drm_dp_mst_helper.h> |
| 38 | #include <drm/drm_fixed.h> | 38 | #include <drm/drm_fixed.h> |
| 39 | #include <drm/drm_crtc_helper.h> | 39 | #include <drm/drm_crtc_helper.h> |
| 40 | #include <linux/i2c.h> | 40 | #include <linux/i2c.h> |
| @@ -802,7 +802,7 @@ static int radeon_mm_vram_dump_table_show(struct seq_file *m, void *unused) · 801 unmodified lines | |||
| 802 | TTM_PL_VRAM); | 802 | TTM_PL_VRAM); |
| 803 | struct drm_printer p = drm_seq_file_printer(m); | 803 | struct drm_printer p = drm_seq_file_printer(m); |
| 804 | 804 | ||
| 805 | man->func->debug(man, &p); | 805 | ttm_resource_manager_debug(man, &p); |
| 806 | return 0; | 806 | return 0; |
| 807 | } | 807 | } |
| 808 | 808 | ||
| @@ -820,7 +820,7 @@ static int radeon_mm_gtt_dump_table_show(struct seq_file *m, void *unused) · 11 unmodified lines | |||
| 820 | TTM_PL_TT); | 820 | TTM_PL_TT); |
| 821 | struct drm_printer p = drm_seq_file_printer(m); | 821 | struct drm_printer p = drm_seq_file_printer(m); |
| 822 | 822 | ||
| 823 | man->func->debug(man, &p); | 823 | ttm_resource_manager_debug(man, &p); |
| 824 | return 0; | 824 | return 0; |
| 825 | } | 825 | } |
| 826 | 826 | ||
| @@ -2,11 +2,13 @@ · 1 unmodified line | |||
| 2 | config DRM_ROCKCHIP | 2 | config DRM_ROCKCHIP |
| 3 | tristate "DRM Support for Rockchip" | 3 | tristate "DRM Support for Rockchip" |
| 4 | depends on DRM && ROCKCHIP_IOMMU | 4 | depends on DRM && ROCKCHIP_IOMMU |
| 5 | select DRM_DP_HELPER | ||
| 5 | select DRM_GEM_CMA_HELPER | 6 | select DRM_GEM_CMA_HELPER |
| 6 | select DRM_KMS_HELPER | 7 | select DRM_KMS_HELPER |
| 7 | select DRM_PANEL | 8 | select DRM_PANEL |
| 8 | select VIDEOMODE_HELPERS | 9 | select VIDEOMODE_HELPERS |
| 9 | select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP | 10 | select DRM_ANALOGIX_DP if ROCKCHIP_ANALOGIX_DP |
| 11 | select DRM_DP_HELPER if ROCKCHIP_ANALOGIX_DP | ||
| 10 | select DRM_DW_HDMI if ROCKCHIP_DW_HDMI | 12 | select DRM_DW_HDMI if ROCKCHIP_DW_HDMI |
| 11 | select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI | 13 | select DRM_DW_MIPI_DSI if ROCKCHIP_DW_MIPI_DSI |
| 12 | select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI | 14 | select GENERIC_PHY if ROCKCHIP_DW_MIPI_DSI |
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | #include <drm/drm_atomic.h> | 22 | #include <drm/drm_atomic.h> |
| 23 | #include <drm/drm_atomic_helper.h> | 23 | #include <drm/drm_atomic_helper.h> |
| 24 | #include <drm/bridge/analogix_dp.h> | 24 | #include <drm/bridge/analogix_dp.h> |
| 25 | #include <drm/drm_dp_helper.h> | 25 | #include <drm/dp/drm_dp_helper.h> |
| 26 | #include <drm/drm_of.h> | 26 | #include <drm/drm_of.h> |
| 27 | #include <drm/drm_panel.h> | 27 | #include <drm/drm_panel.h> |
| 28 | #include <drm/drm_probe_helper.h> | 28 | #include <drm/drm_probe_helper.h> |
| @@ -117,7 +117,7 @@ static int rockchip_dp_get_modes(struct analogix_dp_plat_data *plat_data, · 88 unmodified lines | |||
| 117 | { | 117 | { |
| 118 | struct drm_display_info *di = &connector->display_info; | 118 | struct drm_display_info *di = &connector->display_info; |
| 119 | /* VOP couldn't output YUV video format for eDP rightly */ | 119 | /* VOP couldn't output YUV video format for eDP rightly */ |
| 120 | u32 mask = DRM_COLOR_FORMAT_YCRCB444 | DRM_COLOR_FORMAT_YCRCB422; | 120 | u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422; |
| 121 | 121 | ||
| 122 | if ((di->color_formats & mask)) { | 122 | if ((di->color_formats & mask)) { |
| 123 | DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); | 123 | DRM_DEBUG_KMS("Swapping display color format from YUV to RGB\n"); |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | |||
| 16 | #include <sound/hdmi-codec.h> | 16 | #include <sound/hdmi-codec.h> |
| 17 | 17 | ||
| 18 | #include <drm/drm_atomic_helper.h> | 18 | #include <drm/drm_atomic_helper.h> |
| 19 | #include <drm/drm_dp_helper.h> | 19 | #include <drm/dp/drm_dp_helper.h> |
| 20 | #include <drm/drm_edid.h> | 20 | #include <drm/drm_edid.h> |
| 21 | #include <drm/drm_of.h> | 21 | #include <drm/drm_of.h> |
| 22 | #include <drm/drm_probe_helper.h> | 22 | #include <drm/drm_probe_helper.h> |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | |||
| 7 | #ifndef _CDN_DP_CORE_H | 7 | #ifndef _CDN_DP_CORE_H |
| 8 | #define _CDN_DP_CORE_H | 8 | #define _CDN_DP_CORE_H |
| 9 | 9 | ||
| 10 | #include <drm/drm_dp_helper.h> | 10 | #include <drm/dp/drm_dp_helper.h> |
| 11 | #include <drm/drm_panel.h> | 11 | #include <drm/drm_panel.h> |
| 12 | #include <drm/drm_probe_helper.h> | 12 | #include <drm/drm_probe_helper.h> |
| 13 | 13 | ||
| @@ -20,7 +20,7 @@ · 19 unmodified lines | |||
| 20 | #include <drm/drm_atomic_helper.h> | 20 | #include <drm/drm_atomic_helper.h> |
| 21 | #include <drm/drm_bridge.h> | 21 | #include <drm/drm_bridge.h> |
| 22 | #include <drm/drm_bridge_connector.h> | 22 | #include <drm/drm_bridge_connector.h> |
| 23 | #include <drm/drm_dp_helper.h> | 23 | #include <drm/dp/drm_dp_helper.h> |
| 24 | #include <drm/drm_of.h> | 24 | #include <drm/drm_of.h> |
| 25 | #include <drm/drm_panel.h> | 25 | #include <drm/drm_panel.h> |
| 26 | #include <drm/drm_probe_helper.h> | 26 | #include <drm/drm_probe_helper.h> |
| @@ -11,7 +11,7 @@ · 10 unmodified lines | |||
| 11 | #include <drm/drm_atomic_helper.h> | 11 | #include <drm/drm_atomic_helper.h> |
| 12 | #include <drm/drm_bridge.h> | 12 | #include <drm/drm_bridge.h> |
| 13 | #include <drm/drm_bridge_connector.h> | 13 | #include <drm/drm_bridge_connector.h> |
| 14 | #include <drm/drm_dp_helper.h> | 14 | #include <drm/dp/drm_dp_helper.h> |
| 15 | #include <drm/drm_of.h> | 15 | #include <drm/drm_of.h> |
| 16 | #include <drm/drm_panel.h> | 16 | #include <drm/drm_panel.h> |
| 17 | #include <drm/drm_probe_helper.h> | 17 | #include <drm/drm_probe_helper.h> |
| @@ -7,10 +7,10 @@ · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | #include <linux/random.h> | 8 | #include <linux/random.h> |
| 9 | 9 | ||
| 10 | #include <drm/drm_dp_mst_helper.h> | 10 | #include <drm/dp/drm_dp_mst_helper.h> |
| 11 | #include <drm/drm_print.h> | 11 | #include <drm/drm_print.h> |
| 12 | 12 | ||
| 13 | #include "../drm_dp_mst_topology_internal.h" | 13 | #include "../dp/drm_dp_mst_topology_internal.h" |
| 14 | #include "test-drm_modeset_common.h" | 14 | #include "test-drm_modeset_common.h" |
| 15 | 15 | ||
| 16 | int igt_dp_mst_calc_pbn_mode(void *ignored) | 16 | int igt_dp_mst_calc_pbn_mode(void *ignored) |
| @@ -131,8 +131,10 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in) · 114 unmodified lines | |||
| 131 | return false; | 131 | return false; |
| 132 | 132 | ||
| 133 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | 133 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); |
| 134 | if (!txmsg) | 134 | if (!txmsg) { |
| 135 | kfree(out); | ||
| 135 | return false; | 136 | return false; |
| 137 | } | ||
| 136 | 138 | ||
| 137 | drm_dp_encode_sideband_req(in, txmsg); | 139 | drm_dp_encode_sideband_req(in, txmsg); |
| 138 | ret = drm_dp_decode_sideband_req(txmsg, out); | 140 | ret = drm_dp_decode_sideband_req(txmsg, out); |
| @@ -87,11 +87,15 @@ int igt_check_plane_state(void *ignored) · 86 unmodified lines | |||
| 87 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) | 87 | DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC) |
| 88 | }, | 88 | }, |
| 89 | }; | 89 | }; |
| 90 | struct drm_plane plane = { | ||
| 91 | .dev = NULL | ||
| 92 | }; | ||
| 90 | struct drm_framebuffer fb = { | 93 | struct drm_framebuffer fb = { |
| 91 | .width = 2048, | 94 | .width = 2048, |
| 92 | .height = 2048 | 95 | .height = 2048 |
| 93 | }; | 96 | }; |
| 94 | struct drm_plane_state plane_state = { | 97 | struct drm_plane_state plane_state = { |
| 98 | .plane = &plane, | ||
| 95 | .crtc = ZERO_SIZE_PTR, | 99 | .crtc = ZERO_SIZE_PTR, |
| 96 | .fb = &fb, | 100 | .fb = &fb, |
| 97 | .rotation = DRM_MODE_ROTATE_0 | 101 | .rotation = DRM_MODE_ROTATE_0 |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/of_platform.h> | 14 | #include <linux/of_platform.h> |
| 15 | #include <linux/pm_runtime.h> | 15 | #include <linux/pm_runtime.h> |
| 16 | 16 | ||
| 17 | #include <drm/drm_aperture.h> | ||
| 17 | #include <drm/drm_atomic.h> | 18 | #include <drm/drm_atomic.h> |
| 18 | #include <drm/drm_atomic_helper.h> | 19 | #include <drm/drm_atomic_helper.h> |
| 19 | #include <drm/drm_drv.h> | 20 | #include <drm/drm_drv.h> |
| @@ -183,6 +184,10 @@ static int stm_drm_platform_probe(struct platform_device *pdev) · 163 unmodified lines | |||
| 183 | 184 | ||
| 184 | DRM_DEBUG("%s\n", __func__); | 185 | DRM_DEBUG("%s\n", __func__); |
| 185 | 186 | ||
| 187 | ret = drm_aperture_remove_framebuffers(false, &drv_driver); | ||
| 188 | if (ret) | ||
| 189 | return ret; | ||
| 190 | |||
| 186 | dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); | 191 | dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); |
| 187 | 192 | ||
| 188 | ddev = drm_dev_alloc(&drv_driver, dev); | 193 | ddev = drm_dev_alloc(&drv_driver, dev); |
| @@ -247,14 +247,6 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, · 246 unmodified lines | |||
| 247 | int ret, bpp; | 247 | int ret, bpp; |
| 248 | u32 val; | 248 | u32 val; |
| 249 | 249 | ||
| 250 | /* Update lane capabilities according to hw version */ | ||
| 251 | dsi->lane_min_kbps = LANE_MIN_KBPS; | ||
| 252 | dsi->lane_max_kbps = LANE_MAX_KBPS; | ||
| 253 | if (dsi->hw_version == HWVER_131) { | ||
| 254 | dsi->lane_min_kbps *= 2; | ||
| 255 | dsi->lane_max_kbps *= 2; | ||
| 256 | } | ||
| 257 | |||
| 258 | pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); | 250 | pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); |
| 259 | 251 | ||
| 260 | /* Compute requested pll out */ | 252 | /* Compute requested pll out */ |
| @@ -330,6 +322,103 @@ dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, · 69 unmodified lines | |||
| 330 | return 0; | 322 | return 0; |
| 331 | } | 323 | } |
| 332 | 324 | ||
| 325 | #define CLK_TOLERANCE_HZ 50 | ||
| 326 | |||
| 327 | static enum drm_mode_status | ||
| 328 | dw_mipi_dsi_stm_mode_valid(void *priv_data, | ||
| 329 | const struct drm_display_mode *mode, | ||
| 330 | unsigned long mode_flags, u32 lanes, u32 format) | ||
| 331 | { | ||
| 332 | struct dw_mipi_dsi_stm *dsi = priv_data; | ||
| 333 | unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz; | ||
| 334 | int ret, bpp; | ||
| 335 | |||
| 336 | bpp = mipi_dsi_pixel_format_to_bpp(format); | ||
| 337 | if (bpp < 0) | ||
| 338 | return MODE_BAD; | ||
| 339 | |||
| 340 | /* Compute requested pll out */ | ||
| 341 | pll_out_khz = mode->clock * bpp / lanes; | ||
| 342 | |||
| 343 | if (pll_out_khz > dsi->lane_max_kbps) | ||
| 344 | return MODE_CLOCK_HIGH; | ||
| 345 | |||
| 346 | if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) { | ||
| 347 | /* Add 20% to pll out to be higher than pixel bw */ | ||
| 348 | pll_out_khz = (pll_out_khz * 12) / 10; | ||
| 349 | } else { | ||
| 350 | if (pll_out_khz < dsi->lane_min_kbps) | ||
| 351 | return MODE_CLOCK_LOW; | ||
| 352 | } | ||
| 353 | |||
| 354 | /* Compute best pll parameters */ | ||
| 355 | idf = 0; | ||
| 356 | ndiv = 0; | ||
| 357 | odf = 0; | ||
| 358 | pll_in_khz = clk_get_rate(dsi->pllref_clk) / 1000; | ||
| 359 | ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf); | ||
| 360 | if (ret) { | ||
| 361 | DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); | ||
| 362 | return MODE_ERROR; | ||
| 363 | } | ||
| 364 | |||
| 365 | if (!(mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) { | ||
| 366 | unsigned int px_clock_hz, target_px_clock_hz, lane_mbps; | ||
| 367 | int dsi_short_packet_size_px, hfp, hsync, hbp, delay_to_lp; | ||
| 368 | struct dw_mipi_dsi_dphy_timing dphy_timing; | ||
| 369 | |||
| 370 | /* Get the adjusted pll out value */ | ||
| 371 | pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); | ||
| 372 | |||
| 373 | px_clock_hz = DIV_ROUND_CLOSEST_ULL(1000ULL * pll_out_khz * lanes, bpp); | ||
| 374 | target_px_clock_hz = mode->clock * 1000; | ||
| 375 | /* | ||
| 376 | * Filter modes according to the clock value, particularly useful for | ||
| 377 | * hdmi modes that require precise pixel clocks. | ||
| 378 | */ | ||
| 379 | if (px_clock_hz < target_px_clock_hz - CLK_TOLERANCE_HZ || | ||
| 380 | px_clock_hz > target_px_clock_hz + CLK_TOLERANCE_HZ) | ||
| 381 | return MODE_CLOCK_RANGE; | ||
| 382 | |||
| 383 | /* sync packets are codes as DSI short packets (4 bytes) */ | ||
| 384 | dsi_short_packet_size_px = DIV_ROUND_UP(4 * BITS_PER_BYTE, bpp); | ||
| 385 | |||
| 386 | hfp = mode->hsync_start - mode->hdisplay; | ||
| 387 | hsync = mode->hsync_end - mode->hsync_start; | ||
| 388 | hbp = mode->htotal - mode->hsync_end; | ||
| 389 | |||
| 390 | /* hsync must be longer than 4 bytes HSS packets */ | ||
| 391 | if (hsync < dsi_short_packet_size_px) | ||
| 392 | return MODE_HSYNC_NARROW; | ||
| 393 | |||
| 394 | if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) { | ||
| 395 | /* HBP must be longer than 4 bytes HSE packets */ | ||
| 396 | if (hbp < dsi_short_packet_size_px) | ||
| 397 | return MODE_HSYNC_NARROW; | ||
| 398 | hbp -= dsi_short_packet_size_px; | ||
| 399 | } else { | ||
| 400 | /* With sync events HBP extends in the hsync */ | ||
| 401 | hbp += hsync - dsi_short_packet_size_px; | ||
| 402 | } | ||
| 403 | |||
| 404 | lane_mbps = pll_out_khz / 1000; | ||
| 405 | ret = dw_mipi_dsi_phy_get_timing(priv_data, lane_mbps, &dphy_timing); | ||
| 406 | if (ret) | ||
| 407 | return MODE_ERROR; | ||
| 408 | /* | ||
| 409 | * In non-burst mode DSI has to enter in LP during HFP | ||
| 410 | * (horizontal front porch) or HBP (horizontal back porch) to | ||
| 411 | * resync with LTDC pixel clock. | ||
| 412 | */ | ||
| 413 | delay_to_lp = DIV_ROUND_UP((dphy_timing.data_hs2lp + dphy_timing.data_lp2hs) * | ||
| 414 | lanes * BITS_PER_BYTE, bpp); | ||
| 415 | if (hfp < delay_to_lp && hbp < delay_to_lp) | ||
| 416 | return MODE_HSYNC; | ||
| 417 | } | ||
| 418 | |||
| 419 | return MODE_OK; | ||
| 420 | } | ||
| 421 | |||
| 333 | static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { | 422 | static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { |
| 334 | .init = dw_mipi_dsi_phy_init, | 423 | .init = dw_mipi_dsi_phy_init, |
| 335 | .power_on = dw_mipi_dsi_phy_power_on, | 424 | .power_on = dw_mipi_dsi_phy_power_on, |
| @@ -340,6 +429,7 @@ static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = { · 4 unmodified lines | |||
| 340 | 429 | ||
| 341 | static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { | 430 | static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = { |
| 342 | .max_data_lanes = 2, | 431 | .max_data_lanes = 2, |
| 432 | .mode_valid = dw_mipi_dsi_stm_mode_valid, | ||
| 343 | .phy_ops = &dw_mipi_dsi_stm_phy_ops, | 433 | .phy_ops = &dw_mipi_dsi_stm_phy_ops, |
| 344 | }; | 434 | }; |
| 345 | 435 | ||
| @@ -417,6 +507,14 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) · 71 unmodified lines | |||
| 417 | goto err_dsi_probe; | 507 | goto err_dsi_probe; |
| 418 | } | 508 | } |
| 419 | 509 | ||
| 510 | /* set lane capabilities according to hw version */ | ||
| 511 | dsi->lane_min_kbps = LANE_MIN_KBPS; | ||
| 512 | dsi->lane_max_kbps = LANE_MAX_KBPS; | ||
| 513 | if (dsi->hw_version == HWVER_131) { | ||
| 514 | dsi->lane_min_kbps *= 2; | ||
| 515 | dsi->lane_max_kbps *= 2; | ||
| 516 | } | ||
| 517 | |||
| 420 | dw_mipi_dsi_stm_plat_data.base = dsi->base; | 518 | dw_mipi_dsi_stm_plat_data.base = dsi->base; |
| 421 | dw_mipi_dsi_stm_plat_data.priv_data = dsi; | 519 | dw_mipi_dsi_stm_plat_data.priv_data = dsi; |
| 422 | 520 | ||
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include <linux/pinctrl/consumer.h> | 18 | #include <linux/pinctrl/consumer.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/pm_runtime.h> | 20 | #include <linux/pm_runtime.h> |
| 21 | #include <linux/regmap.h> | ||
| 21 | #include <linux/reset.h> | 22 | #include <linux/reset.h> |
| 22 | 23 | ||
| 23 | #include <drm/drm_atomic.h> | 24 | #include <drm/drm_atomic.h> |
| @@ -46,15 +47,15 @@ · 22 unmodified lines | |||
| 46 | #define HWVER_10200 0x010200 | 47 | #define HWVER_10200 0x010200 |
| 47 | #define HWVER_10300 0x010300 | 48 | #define HWVER_10300 0x010300 |
| 48 | #define HWVER_20101 0x020101 | 49 | #define HWVER_20101 0x020101 |
| 50 | #define HWVER_40100 0x040100 | ||
| 49 | 51 | ||
| 50 | /* | 52 | /* |
| 51 | * The address of some registers depends on the HW version: such registers have | 53 | * The address of some registers depends on the HW version: such registers have |
| 52 | * an extra offset specified with reg_ofs. | 54 | * an extra offset specified with layer_ofs. |
| 53 | */ | 55 | */ |
| 54 | #define REG_OFS_NONE 0 | 56 | #define LAY_OFS_0 0x80 |
| 55 | #define REG_OFS_4 4 /* Insertion of "Layer Conf. 2" reg */ | 57 | #define LAY_OFS_1 0x100 |
| 56 | #define REG_OFS (ldev->caps.reg_ofs) | 58 | #define LAY_OFS (ldev->caps.layer_ofs) |
| 57 | #define LAY_OFS 0x80 /* Register Offset between 2 layers */ | ||
| 58 | 59 | ||
| 59 | /* Global register offsets */ | 60 | /* Global register offsets */ |
| 60 | #define LTDC_IDR 0x0000 /* IDentification */ | 61 | #define LTDC_IDR 0x0000 /* IDentification */ |
| @@ -75,29 +76,35 @@ · 14 unmodified lines | |||
| 75 | #define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */ | 76 | #define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */ |
| 76 | #define LTDC_CPSR 0x0044 /* Current Position Status */ | 77 | #define LTDC_CPSR 0x0044 /* Current Position Status */ |
| 77 | #define LTDC_CDSR 0x0048 /* Current Display Status */ | 78 | #define LTDC_CDSR 0x0048 /* Current Display Status */ |
| 79 | #define LTDC_EDCR 0x0060 /* External Display Control */ | ||
| 80 | #define LTDC_FUT 0x0090 /* Fifo underrun Threshold */ | ||
| 78 | 81 | ||
| 79 | /* Layer register offsets */ | 82 | /* Layer register offsets */ |
| 80 | #define LTDC_L1LC1R (0x80) /* L1 Layer Configuration 1 */ | 83 | #define LTDC_L1C0R (ldev->caps.layer_regs[0]) /* L1 configuration 0 */ |
| 81 | #define LTDC_L1LC2R (0x84) /* L1 Layer Configuration 2 */ | 84 | #define LTDC_L1C1R (ldev->caps.layer_regs[1]) /* L1 configuration 1 */ |
| 82 | #define LTDC_L1CR (0x84 + REG_OFS)/* L1 Control */ | 85 | #define LTDC_L1RCR (ldev->caps.layer_regs[2]) /* L1 reload control */ |
| 83 | #define LTDC_L1WHPCR (0x88 + REG_OFS)/* L1 Window Hor Position Config */ | 86 | #define LTDC_L1CR (ldev->caps.layer_regs[3]) /* L1 control register */ |
| 84 | #define LTDC_L1WVPCR (0x8C + REG_OFS)/* L1 Window Vert Position Config */ | 87 | #define LTDC_L1WHPCR (ldev->caps.layer_regs[4]) /* L1 window horizontal position configuration */ |
| 85 | #define LTDC_L1CKCR (0x90 + REG_OFS)/* L1 Color Keying Configuration */ | 88 | #define LTDC_L1WVPCR (ldev->caps.layer_regs[5]) /* L1 window vertical position configuration */ |
| 86 | #define LTDC_L1PFCR (0x94 + REG_OFS)/* L1 Pixel Format Configuration */ | 89 | #define LTDC_L1CKCR (ldev->caps.layer_regs[6]) /* L1 color keying configuration */ |
| 87 | #define LTDC_L1CACR (0x98 + REG_OFS)/* L1 Constant Alpha Config */ | 90 | #define LTDC_L1PFCR (ldev->caps.layer_regs[7]) /* L1 pixel format configuration */ |
| 88 | #define LTDC_L1DCCR (0x9C + REG_OFS)/* L1 Default Color Configuration */ | 91 | #define LTDC_L1CACR (ldev->caps.layer_regs[8]) /* L1 constant alpha configuration */ |
| 89 | #define LTDC_L1BFCR (0xA0 + REG_OFS)/* L1 Blend Factors Configuration */ | 92 | #define LTDC_L1DCCR (ldev->caps.layer_regs[9]) /* L1 default color configuration */ |
| 90 | #define LTDC_L1FBBCR (0xA4 + REG_OFS)/* L1 FrameBuffer Bus Control */ | 93 | #define LTDC_L1BFCR (ldev->caps.layer_regs[10]) /* L1 blending factors configuration */ |
| 91 | #define LTDC_L1AFBCR (0xA8 + REG_OFS)/* L1 AuxFB Control */ | 94 | #define LTDC_L1BLCR (ldev->caps.layer_regs[11]) /* L1 burst length configuration */ |
| 92 | #define LTDC_L1CFBAR (0xAC + REG_OFS)/* L1 Color FrameBuffer Address */ | 95 | #define LTDC_L1PCR (ldev->caps.layer_regs[12]) /* L1 planar configuration */ |
| 93 | #define LTDC_L1CFBLR (0xB0 + REG_OFS)/* L1 Color FrameBuffer Length */ | 96 | #define LTDC_L1CFBAR (ldev->caps.layer_regs[13]) /* L1 color frame buffer address */ |
| 94 | #define LTDC_L1CFBLNR (0xB4 + REG_OFS)/* L1 Color FrameBuffer Line Nb */ | 97 | #define LTDC_L1CFBLR (ldev->caps.layer_regs[14]) /* L1 color frame buffer length */ |
| 95 | #define LTDC_L1AFBAR (0xB8 + REG_OFS)/* L1 AuxFB Address */ | 98 | #define LTDC_L1CFBLNR (ldev->caps.layer_regs[15]) /* L1 color frame buffer line number */ |
| 96 | #define LTDC_L1AFBLR (0xBC + REG_OFS)/* L1 AuxFB Length */ | 99 | #define LTDC_L1AFBA0R (ldev->caps.layer_regs[16]) /* L1 auxiliary frame buffer address 0 */ |
| 97 | #define LTDC_L1AFBLNR (0xC0 + REG_OFS)/* L1 AuxFB Line Number */ | 100 | #define LTDC_L1AFBA1R (ldev->caps.layer_regs[17]) /* L1 auxiliary frame buffer address 1 */ |
| 98 | #define LTDC_L1CLUTWR (0xC4 + REG_OFS)/* L1 CLUT Write */ | 101 | #define LTDC_L1AFBLR (ldev->caps.layer_regs[18]) /* L1 auxiliary frame buffer length */ |
| 99 | #define LTDC_L1YS1R (0xE0 + REG_OFS)/* L1 YCbCr Scale 1 */ | 102 | #define LTDC_L1AFBLNR (ldev->caps.layer_regs[19]) /* L1 auxiliary frame buffer line number */ |
| 100 | #define LTDC_L1YS2R (0xE4 + REG_OFS)/* L1 YCbCr Scale 2 */ | 103 | #define LTDC_L1CLUTWR (ldev->caps.layer_regs[20]) /* L1 CLUT write */ |
| 104 | #define LTDC_L1CYR0R (ldev->caps.layer_regs[21]) /* L1 Conversion YCbCr RGB 0 */ | ||
| 105 | #define LTDC_L1CYR1R (ldev->caps.layer_regs[22]) /* L1 Conversion YCbCr RGB 1 */ | ||
| 106 | #define LTDC_L1FPF0R (ldev->caps.layer_regs[23]) /* L1 Flexible Pixel Format 0 */ | ||
| 107 | #define LTDC_L1FPF1R (ldev->caps.layer_regs[24]) /* L1 Flexible Pixel Format 1 */ | ||
| 101 | 108 | ||
| 102 | /* Bit definitions */ | 109 | /* Bit definitions */ |
| 103 | #define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */ | 110 | #define SSCR_VSH GENMASK(10, 0) /* Vertical Synchronization Height */ |
| @@ -164,6 +171,10 @@ · 60 unmodified lines | |||
| 164 | #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ | 171 | #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ |
| 165 | #define ISR_RRIF BIT(3) /* Register Reload Interrupt Flag */ | 172 | #define ISR_RRIF BIT(3) /* Register Reload Interrupt Flag */ |
| 166 | 173 | ||
| 174 | #define EDCR_OCYEN BIT(25) /* Output Conversion to YCbCr 422: ENable */ | ||
| 175 | #define EDCR_OCYSEL BIT(26) /* Output Conversion to YCbCr 422: SELection of the CCIR */ | ||
| 176 | #define EDCR_OCYCO BIT(27) /* Output Conversion to YCbCr 422: Chrominance Order */ | ||
| 177 | |||
| 167 | #define LXCR_LEN BIT(0) /* Layer ENable */ | 178 | #define LXCR_LEN BIT(0) /* Layer ENable */ |
| 168 | #define LXCR_COLKEN BIT(1) /* Color Keying Enable */ | 179 | #define LXCR_COLKEN BIT(1) /* Color Keying Enable */ |
| 169 | #define LXCR_CLUTEN BIT(4) /* Color Look-Up Table ENable */ | 180 | #define LXCR_CLUTEN BIT(4) /* Color Look-Up Table ENable */ |
| @@ -175,6 +186,7 @@ · 5 unmodified lines | |||
| 175 | #define LXWVPCR_WVSPPOS GENMASK(26, 16) /* Window Vertical StoP POSition */ | 186 | #define LXWVPCR_WVSPPOS GENMASK(26, 16) /* Window Vertical StoP POSition */ |
| 176 | 187 | ||
| 177 | #define LXPFCR_PF GENMASK(2, 0) /* Pixel Format */ | 188 | #define LXPFCR_PF GENMASK(2, 0) /* Pixel Format */ |
| 189 | #define PF_FLEXIBLE 0x7 /* Flexible Pixel Format selected */ | ||
| 178 | 190 | ||
| 179 | #define LXCACR_CONSTA GENMASK(7, 0) /* CONSTant Alpha */ | 191 | #define LXCACR_CONSTA GENMASK(7, 0) /* CONSTant Alpha */ |
| 180 | 192 | ||
| @@ -186,6 +198,25 @@ · 5 unmodified lines | |||
| 186 | 198 | ||
| 187 | #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ | 199 | #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ |
| 188 | 200 | ||
| 201 | #define LXCR_C1R_YIA BIT(0) /* Ycbcr 422 Interleaved Ability */ | ||
| 202 | #define LXCR_C1R_YSPA BIT(1) /* Ycbcr 420 Semi-Planar Ability */ | ||
| 203 | #define LXCR_C1R_YFPA BIT(2) /* Ycbcr 420 Full-Planar Ability */ | ||
| 204 | #define LXCR_C1R_SCA BIT(31) /* SCaling Ability*/ | ||
| 205 | |||
| 206 | #define LxPCR_YREN BIT(9) /* Y Rescale Enable for the color dynamic range */ | ||
| 207 | #define LxPCR_OF BIT(8) /* Odd pixel First */ | ||
| 208 | #define LxPCR_CBF BIT(7) /* CB component First */ | ||
| 209 | #define LxPCR_YF BIT(6) /* Y component First */ | ||
| 210 | #define LxPCR_YCM GENMASK(5, 4) /* Ycbcr Conversion Mode */ | ||
| 211 | #define YCM_I 0x0 /* Interleaved 422 */ | ||
| 212 | #define YCM_SP 0x1 /* Semi-Planar 420 */ | ||
| 213 | #define YCM_FP 0x2 /* Full-Planar 420 */ | ||
| 214 | #define LxPCR_YCEN BIT(3) /* YCbCr-to-RGB Conversion Enable */ | ||
| 215 | |||
| 216 | #define LXRCR_IMR BIT(0) /* IMmediate Reload */ | ||
| 217 | #define LXRCR_VBR BIT(1) /* Vertical Blanking Reload */ | ||
| 218 | #define LXRCR_GRMSK BIT(2) /* Global (centralized) Reload MaSKed */ | ||
| 219 | |||
| 189 | #define CLUT_SIZE 256 | 220 | #define CLUT_SIZE 256 |
| 190 | 221 | ||
| 191 | #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ | 222 | #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ |
| @@ -201,8 +232,12 @@ enum ltdc_pix_fmt { · 9 unmodified lines | |||
| 201 | /* RGB formats */ | 232 | /* RGB formats */ |
| 202 | PF_ARGB8888, /* ARGB [32 bits] */ | 233 | PF_ARGB8888, /* ARGB [32 bits] */ |
| 203 | PF_RGBA8888, /* RGBA [32 bits] */ | 234 | PF_RGBA8888, /* RGBA [32 bits] */ |
| 235 | PF_ABGR8888, /* ABGR [32 bits] */ | ||
| 236 | PF_BGRA8888, /* BGRA [32 bits] */ | ||
| 204 | PF_RGB888, /* RGB [24 bits] */ | 237 | PF_RGB888, /* RGB [24 bits] */ |
| 238 | PF_BGR888, /* BGR [24 bits] */ | ||
| 205 | PF_RGB565, /* RGB [16 bits] */ | 239 | PF_RGB565, /* RGB [16 bits] */ |
| 240 | PF_BGR565, /* BGR [16 bits] */ | ||
| 206 | PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ | 241 | PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ |
| 207 | PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ | 242 | PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ |
| 208 | /* Indexed formats */ | 243 | /* Indexed formats */ |
| @@ -234,36 +269,198 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a1[NB_PF] = { · 25 unmodified lines | |||
| 234 | PF_ARGB4444 /* 0x07 */ | 269 | PF_ARGB4444 /* 0x07 */ |
| 235 | }; | 270 | }; |
| 236 | 271 | ||
| 237 | static const u64 ltdc_format_modifiers[] = { | 272 | static const enum ltdc_pix_fmt ltdc_pix_fmt_a2[NB_PF] = { |
| 238 | DRM_FORMAT_MOD_LINEAR, | 273 | PF_ARGB8888, /* 0x00 */ |
| 239 | DRM_FORMAT_MOD_INVALID | 274 | PF_ABGR8888, /* 0x01 */ |
| 275 | PF_RGBA8888, /* 0x02 */ | ||
| 276 | PF_BGRA8888, /* 0x03 */ | ||
| 277 | PF_RGB565, /* 0x04 */ | ||
| 278 | PF_BGR565, /* 0x05 */ | ||
| 279 | PF_RGB888, /* 0x06 */ | ||
| 280 | PF_NONE /* 0x07 */ | ||
| 240 | }; | 281 | }; |
| 241 | 282 | ||
| 242 | static inline u32 reg_read(void __iomem *base, u32 reg) | 283 | static const u32 ltdc_drm_fmt_a0[] = { |
| 243 | { | 284 | DRM_FORMAT_ARGB8888, |
| 244 | return readl_relaxed(base + reg); | 285 | DRM_FORMAT_XRGB8888, |
| 245 | } | 286 | DRM_FORMAT_RGB888, |
| 287 | DRM_FORMAT_RGB565, | ||
| 288 | DRM_FORMAT_ARGB1555, | ||
| 289 | DRM_FORMAT_XRGB1555, | ||
| 290 | DRM_FORMAT_ARGB4444, | ||
| 291 | DRM_FORMAT_XRGB4444, | ||
| 292 | DRM_FORMAT_C8 | ||
| 293 | }; | ||
| 246 | 294 | ||
| 247 | static inline void reg_write(void __iomem *base, u32 reg, u32 val) | 295 | static const u32 ltdc_drm_fmt_a1[] = { |
| 248 | { | 296 | DRM_FORMAT_ARGB8888, |
| 249 | writel_relaxed(val, base + reg); | 297 | DRM_FORMAT_XRGB8888, |
| 250 | } | 298 | DRM_FORMAT_RGB888, |
| 299 | DRM_FORMAT_RGB565, | ||
| 300 | DRM_FORMAT_RGBA8888, | ||
| 301 | DRM_FORMAT_RGBX8888, | ||
| 302 | DRM_FORMAT_ARGB1555, | ||
| 303 | DRM_FORMAT_XRGB1555, | ||
| 304 | DRM_FORMAT_ARGB4444, | ||
| 305 | DRM_FORMAT_XRGB4444, | ||
| 306 | DRM_FORMAT_C8 | ||
| 307 | }; | ||
| 251 | 308 | ||
| 252 | static inline void reg_set(void __iomem *base, u32 reg, u32 mask) | 309 | static const u32 ltdc_drm_fmt_a2[] = { |
| 253 | { | 310 | DRM_FORMAT_ARGB8888, |
| 254 | reg_write(base, reg, reg_read(base, reg) | mask); | 311 | DRM_FORMAT_XRGB8888, |
| 255 | } | 312 | DRM_FORMAT_ABGR8888, |
| 313 | DRM_FORMAT_XBGR8888, | ||
| 314 | DRM_FORMAT_RGBA8888, | ||
| 315 | DRM_FORMAT_RGBX8888, | ||
| 316 | DRM_FORMAT_BGRA8888, | ||
| 317 | DRM_FORMAT_BGRX8888, | ||
| 318 | DRM_FORMAT_RGB565, | ||
| 319 | DRM_FORMAT_BGR565, | ||
| 320 | DRM_FORMAT_RGB888, | ||
| 321 | DRM_FORMAT_BGR888, | ||
| 322 | DRM_FORMAT_ARGB1555, | ||
| 323 | DRM_FORMAT_XRGB1555, | ||
| 324 | DRM_FORMAT_ARGB4444, | ||
| 325 | DRM_FORMAT_XRGB4444, | ||
| 326 | DRM_FORMAT_C8 | ||
| 327 | }; | ||
| 256 | 328 | ||
| 257 | static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) | 329 | static const u32 ltdc_drm_fmt_ycbcr_cp[] = { |
| 258 | { | 330 | DRM_FORMAT_YUYV, |
| 259 | reg_write(base, reg, reg_read(base, reg) & ~mask); | 331 | DRM_FORMAT_YVYU, |
| 260 | } | 332 | DRM_FORMAT_UYVY, |
| 333 | DRM_FORMAT_VYUY | ||
| 334 | }; | ||
| 261 | 335 | ||
| 262 | static inline void reg_update_bits(void __iomem *base, u32 reg, u32 mask, | 336 | static const u32 ltdc_drm_fmt_ycbcr_sp[] = { |
| 263 | u32 val) | 337 | DRM_FORMAT_NV12, |
| 264 | { | 338 | DRM_FORMAT_NV21 |
| 265 | reg_write(base, reg, (reg_read(base, reg) & ~mask) | val); | 339 | }; |
| 266 | } | 340 | |
| 341 | static const u32 ltdc_drm_fmt_ycbcr_fp[] = { | ||
| 342 | DRM_FORMAT_YUV420, | ||
| 343 | DRM_FORMAT_YVU420 | ||
| 344 | }; | ||
| 345 | |||
| 346 | /* Layer register offsets */ | ||
| 347 | static const u32 ltdc_layer_regs_a0[] = { | ||
| 348 | 0x80, /* L1 configuration 0 */ | ||
| 349 | 0x00, /* not available */ | ||
| 350 | 0x00, /* not available */ | ||
| 351 | 0x84, /* L1 control register */ | ||
| 352 | 0x88, /* L1 window horizontal position configuration */ | ||
| 353 | 0x8c, /* L1 window vertical position configuration */ | ||
| 354 | 0x90, /* L1 color keying configuration */ | ||
| 355 | 0x94, /* L1 pixel format configuration */ | ||
| 356 | 0x98, /* L1 constant alpha configuration */ | ||
| 357 | 0x9c, /* L1 default color configuration */ | ||
| 358 | 0xa0, /* L1 blending factors configuration */ | ||
| 359 | 0x00, /* not available */ | ||
| 360 | 0x00, /* not available */ | ||
| 361 | 0xac, /* L1 color frame buffer address */ | ||
| 362 | 0xb0, /* L1 color frame buffer length */ | ||
| 363 | 0xb4, /* L1 color frame buffer line number */ | ||
| 364 | 0x00, /* not available */ | ||
| 365 | 0x00, /* not available */ | ||
| 366 | 0x00, /* not available */ | ||
| 367 | 0x00, /* not available */ | ||
| 368 | 0xc4, /* L1 CLUT write */ | ||
| 369 | 0x00, /* not available */ | ||
| 370 | 0x00, /* not available */ | ||
| 371 | 0x00, /* not available */ | ||
| 372 | 0x00 /* not available */ | ||
| 373 | }; | ||
| 374 | |||
| 375 | static const u32 ltdc_layer_regs_a1[] = { | ||
| 376 | 0x80, /* L1 configuration 0 */ | ||
| 377 | 0x84, /* L1 configuration 1 */ | ||
| 378 | 0x00, /* L1 reload control */ | ||
| 379 | 0x88, /* L1 control register */ | ||
| 380 | 0x8c, /* L1 window horizontal position configuration */ | ||
| 381 | 0x90, /* L1 window vertical position configuration */ | ||
| 382 | 0x94, /* L1 color keying configuration */ | ||
| 383 | 0x98, /* L1 pixel format configuration */ | ||
| 384 | 0x9c, /* L1 constant alpha configuration */ | ||
| 385 | 0xa0, /* L1 default color configuration */ | ||
| 386 | 0xa4, /* L1 blending factors configuration */ | ||
| 387 | 0xa8, /* L1 burst length configuration */ | ||
| 388 | 0x00, /* not available */ | ||
| 389 | 0xac, /* L1 color frame buffer address */ | ||
| 390 | 0xb0, /* L1 color frame buffer length */ | ||
| 391 | 0xb4, /* L1 color frame buffer line number */ | ||
| 392 | 0xb8, /* L1 auxiliary frame buffer address 0 */ | ||
| 393 | 0xbc, /* L1 auxiliary frame buffer address 1 */ | ||
| 394 | 0xc0, /* L1 auxiliary frame buffer length */ | ||
| 395 | 0xc4, /* L1 auxiliary frame buffer line number */ | ||
| 396 | 0xc8, /* L1 CLUT write */ | ||
| 397 | 0x00, /* not available */ | ||
| 398 | 0x00, /* not available */ | ||
| 399 | 0x00, /* not available */ | ||
| 400 | 0x00 /* not available */ | ||
| 401 | }; | ||
| 402 | |||
| 403 | static const u32 ltdc_layer_regs_a2[] = { | ||
| 404 | 0x100, /* L1 configuration 0 */ | ||
| 405 | 0x104, /* L1 configuration 1 */ | ||
| 406 | 0x108, /* L1 reload control */ | ||
| 407 | 0x10c, /* L1 control register */ | ||
| 408 | 0x110, /* L1 window horizontal position configuration */ | ||
| 409 | 0x114, /* L1 window vertical position configuration */ | ||
| 410 | 0x118, /* L1 color keying configuration */ | ||
| 411 | 0x11c, /* L1 pixel format configuration */ | ||
| 412 | 0x120, /* L1 constant alpha configuration */ | ||
| 413 | 0x124, /* L1 default color configuration */ | ||
| 414 | 0x128, /* L1 blending factors configuration */ | ||
| 415 | 0x12c, /* L1 burst length configuration */ | ||
| 416 | 0x130, /* L1 planar configuration */ | ||
| 417 | 0x134, /* L1 color frame buffer address */ | ||
| 418 | 0x138, /* L1 color frame buffer length */ | ||
| 419 | 0x13c, /* L1 color frame buffer line number */ | ||
| 420 | 0x140, /* L1 auxiliary frame buffer address 0 */ | ||
| 421 | 0x144, /* L1 auxiliary frame buffer address 1 */ | ||
| 422 | 0x148, /* L1 auxiliary frame buffer length */ | ||
| 423 | 0x14c, /* L1 auxiliary frame buffer line number */ | ||
| 424 | 0x150, /* L1 CLUT write */ | ||
| 425 | 0x16c, /* L1 Conversion YCbCr RGB 0 */ | ||
| 426 | 0x170, /* L1 Conversion YCbCr RGB 1 */ | ||
| 427 | 0x174, /* L1 Flexible Pixel Format 0 */ | ||
| 428 | 0x178 /* L1 Flexible Pixel Format 1 */ | ||
| 429 | }; | ||
| 430 | |||
| 431 | static const u64 ltdc_format_modifiers[] = { | ||
| 432 | DRM_FORMAT_MOD_LINEAR, | ||
| 433 | DRM_FORMAT_MOD_INVALID | ||
| 434 | }; | ||
| 435 | |||
| 436 | static const struct regmap_config stm32_ltdc_regmap_cfg = { | ||
| 437 | .reg_bits = 32, | ||
| 438 | .val_bits = 32, | ||
| 439 | .reg_stride = sizeof(u32), | ||
| 440 | .max_register = 0x400, | ||
| 441 | .use_relaxed_mmio = true, | ||
| 442 | .cache_type = REGCACHE_NONE, | ||
| 443 | }; | ||
| 444 | |||
| 445 | static const u32 ltdc_ycbcr2rgb_coeffs[DRM_COLOR_ENCODING_MAX][DRM_COLOR_RANGE_MAX][2] = { | ||
| 446 | [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = { | ||
| 447 | 0x02040199, /* (b_cb = 516 / r_cr = 409) */ | ||
| 448 | 0x006400D0 /* (g_cb = 100 / g_cr = 208) */ | ||
| 449 | }, | ||
| 450 | [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = { | ||
| 451 | 0x01C60167, /* (b_cb = 454 / r_cr = 359) */ | ||
| 452 | 0x005800B7 /* (g_cb = 88 / g_cr = 183) */ | ||
| 453 | }, | ||
| 454 | [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = { | ||
| 455 | 0x021D01CB, /* (b_cb = 541 / r_cr = 459) */ | ||
| 456 | 0x00370089 /* (g_cb = 55 / g_cr = 137) */ | ||
| 457 | }, | ||
| 458 | [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = { | ||
| 459 | 0x01DB0193, /* (b_cb = 475 / r_cr = 403) */ | ||
| 460 | 0x00300078 /* (g_cb = 48 / g_cr = 120) */ | ||
| 461 | } | ||
| 462 | /* BT2020 not supported */ | ||
| 463 | }; | ||
| 267 | 464 | ||
| 268 | static inline struct ltdc_device *crtc_to_ltdc(struct drm_crtc *crtc) | 465 | static inline struct ltdc_device *crtc_to_ltdc(struct drm_crtc *crtc) |
| 269 | { | 466 | { |
| @@ -289,16 +486,30 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) · 19 unmodified lines | |||
| 289 | case DRM_FORMAT_XRGB8888: | 486 | case DRM_FORMAT_XRGB8888: |
| 290 | pf = PF_ARGB8888; | 487 | pf = PF_ARGB8888; |
| 291 | break; | 488 | break; |
| 489 | case DRM_FORMAT_ABGR8888: | ||
| 490 | case DRM_FORMAT_XBGR8888: | ||
| 491 | pf = PF_ABGR8888; | ||
| 492 | break; | ||
| 292 | case DRM_FORMAT_RGBA8888: | 493 | case DRM_FORMAT_RGBA8888: |
| 293 | case DRM_FORMAT_RGBX8888: | 494 | case DRM_FORMAT_RGBX8888: |
| 294 | pf = PF_RGBA8888; | 495 | pf = PF_RGBA8888; |
| 295 | break; | 496 | break; |
| 497 | case DRM_FORMAT_BGRA8888: | ||
| 498 | case DRM_FORMAT_BGRX8888: | ||
| 499 | pf = PF_BGRA8888; | ||
| 500 | break; | ||
| 296 | case DRM_FORMAT_RGB888: | 501 | case DRM_FORMAT_RGB888: |
| 297 | pf = PF_RGB888; | 502 | pf = PF_RGB888; |
| 298 | break; | 503 | break; |
| 504 | case DRM_FORMAT_BGR888: | ||
| 505 | pf = PF_BGR888; | ||
| 506 | break; | ||
| 299 | case DRM_FORMAT_RGB565: | 507 | case DRM_FORMAT_RGB565: |
| 300 | pf = PF_RGB565; | 508 | pf = PF_RGB565; |
| 301 | break; | 509 | break; |
| 510 | case DRM_FORMAT_BGR565: | ||
| 511 | pf = PF_BGR565; | ||
| 512 | break; | ||
| 302 | case DRM_FORMAT_ARGB1555: | 513 | case DRM_FORMAT_ARGB1555: |
| 303 | case DRM_FORMAT_XRGB1555: | 514 | case DRM_FORMAT_XRGB1555: |
| 304 | pf = PF_ARGB1555; | 515 | pf = PF_ARGB1555; |
| @@ -319,49 +530,138 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) · 14 unmodified lines | |||
| 319 | return pf; | 530 | return pf; |
| 320 | } | 531 | } |
| 321 | 532 | ||
| 322 | static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf) | 533 | static inline u32 ltdc_set_flexible_pixel_format(struct drm_plane *plane, enum ltdc_pix_fmt pix_fmt) |
| 323 | { | 534 | { |
| 324 | switch (pf) { | 535 | struct ltdc_device *ldev = plane_to_ltdc(plane); |
| 325 | case PF_ARGB8888: | 536 | u32 lofs = plane->index * LAY_OFS, ret = PF_FLEXIBLE; |
| 326 | return DRM_FORMAT_ARGB8888; | 537 | int psize, alen, apos, rlen, rpos, glen, gpos, blen, bpos; |
| 327 | case PF_RGBA8888: | 538 | |
| 328 | return DRM_FORMAT_RGBA8888; | 539 | switch (pix_fmt) { |
| 329 | case PF_RGB888: | 540 | case PF_BGR888: |
| 330 | return DRM_FORMAT_RGB888; | 541 | psize = 3; |
| 331 | case PF_RGB565: | 542 | alen = 0; apos = 0; rlen = 8; rpos = 0; |
| 332 | return DRM_FORMAT_RGB565; | 543 | glen = 8; gpos = 8; blen = 8; bpos = 16; |
| 544 | break; | ||
| 333 | case PF_ARGB1555: | 545 | case PF_ARGB1555: |
| 334 | return DRM_FORMAT_ARGB1555; | 546 | psize = 2; |
| 547 | alen = 1; apos = 15; rlen = 5; rpos = 10; | ||
| 548 | glen = 5; gpos = 5; blen = 5; bpos = 0; | ||
| 549 | break; | ||
| 335 | case PF_ARGB4444: | 550 | case PF_ARGB4444: |
| 336 | return DRM_FORMAT_ARGB4444; | 551 | psize = 2; |
| 552 | alen = 4; apos = 12; rlen = 4; rpos = 8; | ||
| 553 | glen = 4; gpos = 4; blen = 4; bpos = 0; | ||
| 554 | break; | ||
| 337 | case PF_L8: | 555 | case PF_L8: |
| 338 | return DRM_FORMAT_C8; | 556 | psize = 1; |
| 339 | case PF_AL44: /* No DRM support */ | 557 | alen = 0; apos = 0; rlen = 8; rpos = 0; |
| 340 | case PF_AL88: /* No DRM support */ | 558 | glen = 8; gpos = 0; blen = 8; bpos = 0; |
| 341 | case PF_NONE: | 559 | break; |
| 560 | case PF_AL44: | ||
| 561 | psize = 1; | ||
| 562 | alen = 4; apos = 4; rlen = 4; rpos = 0; | ||
| 563 | glen = 4; gpos = 0; blen = 4; bpos = 0; | ||
| 564 | break; | ||
| 565 | case PF_AL88: | ||
| 566 | psize = 2; | ||
| 567 | alen = 8; apos = 8; rlen = 8; rpos = 0; | ||
| 568 | glen = 8; gpos = 0; blen = 8; bpos = 0; | ||
| 569 | break; | ||
| 342 | default: | 570 | default: |
| 343 | return 0; | 571 | ret = NB_PF; /* error case, trace msg is handled by the caller */ |
| 572 | break; | ||
| 344 | } | 573 | } |
| 574 | |||
| 575 | if (ret == PF_FLEXIBLE) { | ||
| 576 | regmap_write(ldev->regmap, LTDC_L1FPF0R + lofs, | ||
| 577 | (rlen << 14) + (rpos << 9) + (alen << 5) + apos); | ||
| 578 | |||
| 579 | regmap_write(ldev->regmap, LTDC_L1FPF1R + lofs, | ||
| 580 | (psize << 18) + (blen << 14) + (bpos << 9) + (glen << 5) + gpos); | ||
| 581 | } | ||
| 582 | |||
| 583 | return ret; | ||
| 345 | } | 584 | } |
| 346 | 585 | ||
| 347 | static inline u32 get_pixelformat_without_alpha(u32 drm) | 586 | /* |
| 587 | * All non-alpha color formats derived from native alpha color formats are | ||
| 588 | * either characterized by a FourCC format code | ||
| 589 | */ | ||
| 590 | static inline u32 is_xrgb(u32 drm) | ||
| 348 | { | 591 | { |
| 349 | switch (drm) { | 592 | return ((drm & 0xFF) == 'X' || ((drm >> 8) & 0xFF) == 'X'); |
| 350 | case DRM_FORMAT_ARGB4444: | 593 | } |
| 351 | return DRM_FORMAT_XRGB4444; | 594 | |
| 352 | case DRM_FORMAT_RGBA4444: | 595 | static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fmt) |
| 353 | return DRM_FORMAT_RGBX4444; | 596 | { |
| 354 | case DRM_FORMAT_ARGB1555: | 597 | struct ltdc_device *ldev = plane_to_ltdc(plane); |
| 355 | return DRM_FORMAT_XRGB1555; | 598 | struct drm_plane_state *state = plane->state; |
| 356 | case DRM_FORMAT_RGBA5551: | 599 | u32 lofs = plane->index * LAY_OFS; |
| 357 | return DRM_FORMAT_RGBX5551; | 600 | u32 val; |
| 358 | case DRM_FORMAT_ARGB8888: | 601 | |
| 359 | return DRM_FORMAT_XRGB8888; | 602 | switch (drm_pix_fmt) { |
| 360 | case DRM_FORMAT_RGBA8888: | 603 | case DRM_FORMAT_YUYV: |
| 361 | return DRM_FORMAT_RGBX8888; | 604 | val = (YCM_I << 4) | LxPCR_YF | LxPCR_CBF; |
| 605 | break; | ||
| 606 | case DRM_FORMAT_YVYU: | ||
| 607 | val = (YCM_I << 4) | LxPCR_YF; | ||
| 608 | break; | ||
| 609 | case DRM_FORMAT_UYVY: | ||
| 610 | val = (YCM_I << 4) | LxPCR_CBF; | ||
| 611 | break; | ||
| 612 | case DRM_FORMAT_VYUY: | ||
| 613 | val = (YCM_I << 4); | ||
| 614 | break; | ||
| 615 | case DRM_FORMAT_NV12: | ||
| 616 | val = (YCM_SP << 4) | LxPCR_CBF; | ||
| 617 | break; | ||
| 618 | case DRM_FORMAT_NV21: | ||
| 619 | val = (YCM_SP << 4); | ||
| 620 | break; | ||
| 621 | case DRM_FORMAT_YUV420: | ||
| 622 | case DRM_FORMAT_YVU420: | ||
| 623 | val = (YCM_FP << 4); | ||
| 624 | break; | ||
| 362 | default: | 625 | default: |
| 363 | return 0; | 626 | /* RGB or not a YCbCr supported format */ |
| 627 | break; | ||
| 628 | } | ||
| 629 | |||
| 630 | /* Enable limited range */ | ||
| 631 | if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) | ||
| 632 | val |= LxPCR_YREN; | ||
| 633 | |||
| 634 | /* enable ycbcr conversion */ | ||
| 635 | val |= LxPCR_YCEN; | ||
| 636 | |||
| 637 | regmap_write(ldev->regmap, LTDC_L1PCR + lofs, val); | ||
| 638 | } | ||
| 639 | |||
| 640 | static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane) | ||
| 641 | { | ||
| 642 | struct ltdc_device *ldev = plane_to_ltdc(plane); | ||
| 643 | struct drm_plane_state *state = plane->state; | ||
| 644 | enum drm_color_encoding enc = state->color_encoding; | ||
| 645 | enum drm_color_range ran = state->color_range; | ||
| 646 | u32 lofs = plane->index * LAY_OFS; | ||
| 647 | |||
| 648 | if (enc != DRM_COLOR_YCBCR_BT601 && enc != DRM_COLOR_YCBCR_BT709) { | ||
| 649 | DRM_ERROR("color encoding %d not supported, use bt601 by default\n", enc); | ||
| 650 | /* set by default color encoding to DRM_COLOR_YCBCR_BT601 */ | ||
| 651 | enc = DRM_COLOR_YCBCR_BT601; | ||
| 652 | } | ||
| 653 | |||
| 654 | if (ran != DRM_COLOR_YCBCR_LIMITED_RANGE && ran != DRM_COLOR_YCBCR_FULL_RANGE) { | ||
| 655 | DRM_ERROR("color range %d not supported, use limited range by default\n", ran); | ||
| 656 | /* set by default color range to DRM_COLOR_YCBCR_LIMITED_RANGE */ | ||
| 657 | ran = DRM_COLOR_YCBCR_LIMITED_RANGE; | ||
| 364 | } | 658 | } |
| 659 | |||
| 660 | DRM_DEBUG_DRIVER("Color encoding=%d, range=%d\n", enc, ran); | ||
| 661 | regmap_write(ldev->regmap, LTDC_L1CYR0R + lofs, | ||
| 662 | ltdc_ycbcr2rgb_coeffs[enc][ran][0]); | ||
| 663 | regmap_write(ldev->regmap, LTDC_L1CYR1R + lofs, | ||
| 664 | ltdc_ycbcr2rgb_coeffs[enc][ran][1]); | ||
| 365 | } | 665 | } |
| 366 | 666 | ||
| 367 | static irqreturn_t ltdc_irq_thread(int irq, void *arg) | 667 | static irqreturn_t ltdc_irq_thread(int irq, void *arg) |
| @@ -390,9 +690,13 @@ static irqreturn_t ltdc_irq(int irq, void *arg) · 22 unmodified lines | |||
| 390 | struct drm_device *ddev = arg; | 690 | struct drm_device *ddev = arg; |
| 391 | struct ltdc_device *ldev = ddev->dev_private; | 691 | struct ltdc_device *ldev = ddev->dev_private; |
| 392 | 692 | ||
| 393 | /* Read & Clear the interrupt status */ | 693 | /* |
| 394 | ldev->irq_status = reg_read(ldev->regs, LTDC_ISR); | 694 | * Read & Clear the interrupt status |
| 395 | reg_write(ldev->regs, LTDC_ICR, ldev->irq_status); | 695 | * In order to write / read registers in this critical section |
| 696 | * very quickly, the regmap functions are not used. | ||
| 697 | */ | ||
| 698 | ldev->irq_status = readl_relaxed(ldev->regs + LTDC_ISR); | ||
| 699 | writel_relaxed(ldev->irq_status, ldev->regs + LTDC_ICR); | ||
| 396 | 700 | ||
| 397 | return IRQ_WAKE_THREAD; | 701 | return IRQ_WAKE_THREAD; |
| 398 | } | 702 | } |
| @@ -416,7 +720,7 @@ static void ltdc_crtc_update_clut(struct drm_crtc *crtc) · 17 unmodified lines | |||
| 416 | for (i = 0; i < CLUT_SIZE; i++, lut++) { | 720 | for (i = 0; i < CLUT_SIZE; i++, lut++) { |
| 417 | val = ((lut->red << 8) & 0xff0000) | (lut->green & 0xff00) | | 721 | val = ((lut->red << 8) & 0xff0000) | (lut->green & 0xff00) | |
| 418 | (lut->blue >> 8) | (i << 24); | 722 | (lut->blue >> 8) | (i << 24); |
| 419 | reg_write(ldev->regs, LTDC_L1CLUTWR, val); | 723 | regmap_write(ldev->regmap, LTDC_L1CLUTWR, val); |
| 420 | } | 724 | } |
| 421 | } | 725 | } |
| 422 | 726 | ||
| @@ -431,13 +735,14 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, · 8 unmodified lines | |||
| 431 | pm_runtime_get_sync(ddev->dev); | 735 | pm_runtime_get_sync(ddev->dev); |
| 432 | 736 | ||
| 433 | /* Sets the background color value */ | 737 | /* Sets the background color value */ |
| 434 | reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); | 738 | regmap_write(ldev->regmap, LTDC_BCCR, BCCR_BCBLACK); |
| 435 | 739 | ||
| 436 | /* Enable IRQ */ | 740 | /* Enable IRQ */ |
| 437 | reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | 741 | regmap_set_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); |
| 438 | 742 | ||
| 439 | /* Commit shadow registers = update planes at next vblank */ | 743 | /* Commit shadow registers = update planes at next vblank */ |
| 440 | reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); | 744 | if (!ldev->caps.plane_reg_shadow) |
| 745 | regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); | ||
| 441 | 746 | ||
| 442 | drm_crtc_vblank_on(crtc); | 747 | drm_crtc_vblank_on(crtc); |
| 443 | } | 748 | } |
| @@ -453,10 +758,11 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, · 9 unmodified lines | |||
| 453 | drm_crtc_vblank_off(crtc); | 758 | drm_crtc_vblank_off(crtc); |
| 454 | 759 | ||
| 455 | /* disable IRQ */ | 760 | /* disable IRQ */ |
| 456 | reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); | 761 | regmap_clear_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); |
| 457 | 762 | ||
| 458 | /* immediately commit disable of layers before switching off LTDC */ | 763 | /* immediately commit disable of layers before switching off LTDC */ |
| 459 | reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); | 764 | if (!ldev->caps.plane_reg_shadow) |
| 765 | regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_IMR); | ||
| 460 | 766 | ||
| 461 | pm_runtime_put_sync(ddev->dev); | 767 | pm_runtime_put_sync(ddev->dev); |
| 462 | } | 768 | } |
| @@ -533,6 +839,7 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 70 unmodified lines | |||
| 533 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; | 839 | struct drm_display_mode *mode = &crtc->state->adjusted_mode; |
| 534 | u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; | 840 | u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; |
| 535 | u32 total_width, total_height; | 841 | u32 total_width, total_height; |
| 842 | u32 bus_formats = MEDIA_BUS_FMT_RGB888_1X24; | ||
| 536 | u32 bus_flags = 0; | 843 | u32 bus_flags = 0; |
| 537 | u32 val; | 844 | u32 val; |
| 538 | int ret; | 845 | int ret; |
| @@ -558,8 +865,11 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 19 unmodified lines | |||
| 558 | 865 | ||
| 559 | if (bridge && bridge->timings) | 866 | if (bridge && bridge->timings) |
| 560 | bus_flags = bridge->timings->input_bus_flags; | 867 | bus_flags = bridge->timings->input_bus_flags; |
| 561 | else if (connector) | 868 | else if (connector) { |
| 562 | bus_flags = connector->display_info.bus_flags; | 869 | bus_flags = connector->display_info.bus_flags; |
| 870 | if (connector->display_info.num_bus_formats) | ||
| 871 | bus_formats = connector->display_info.bus_formats[0]; | ||
| 872 | } | ||
| 563 | 873 | ||
| 564 | if (!pm_runtime_active(ddev->dev)) { | 874 | if (!pm_runtime_active(ddev->dev)) { |
| 565 | ret = pm_runtime_get_sync(ddev->dev); | 875 | ret = pm_runtime_get_sync(ddev->dev); |
| @@ -604,26 +914,56 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) · 38 unmodified lines | |||
| 604 | if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) | 914 | if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) |
| 605 | val |= GCR_PCPOL; | 915 | val |= GCR_PCPOL; |
| 606 | 916 | ||
| 607 | reg_update_bits(ldev->regs, LTDC_GCR, | 917 | regmap_update_bits(ldev->regmap, LTDC_GCR, |
| 608 | GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); | 918 | GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); |
| 609 | 919 | ||
| 610 | /* Set Synchronization size */ | 920 | /* Set Synchronization size */ |
| 611 | val = (hsync << 16) | vsync; | 921 | val = (hsync << 16) | vsync; |
| 612 | reg_update_bits(ldev->regs, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); | 922 | regmap_update_bits(ldev->regmap, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); |
| 613 | 923 | ||
| 614 | /* Set Accumulated Back porch */ | 924 | /* Set Accumulated Back porch */ |
| 615 | val = (accum_hbp << 16) | accum_vbp; | 925 | val = (accum_hbp << 16) | accum_vbp; |
| 616 | reg_update_bits(ldev->regs, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); | 926 | regmap_update_bits(ldev->regmap, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); |
| 617 | 927 | ||
| 618 | /* Set Accumulated Active Width */ | 928 | /* Set Accumulated Active Width */ |
| 619 | val = (accum_act_w << 16) | accum_act_h; | 929 | val = (accum_act_w << 16) | accum_act_h; |
| 620 | reg_update_bits(ldev->regs, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); | 930 | regmap_update_bits(ldev->regmap, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); |
| 621 | 931 | ||
| 622 | /* Set total width & height */ | 932 | /* Set total width & height */ |
| 623 | val = (total_width << 16) | total_height; | 933 | val = (total_width << 16) | total_height; |
| 624 | reg_update_bits(ldev->regs, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); | 934 | regmap_update_bits(ldev->regmap, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); |
| 625 | 935 | ||
| 626 | reg_write(ldev->regs, LTDC_LIPCR, (accum_act_h + 1)); | 936 | regmap_write(ldev->regmap, LTDC_LIPCR, (accum_act_h + 1)); |
| 937 | |||
| 938 | /* Configure the output format (hw version dependent) */ | ||
| 939 | if (ldev->caps.ycbcr_output) { | ||
| 940 | /* Input video dynamic_range & colorimetry */ | ||
| 941 | int vic = drm_match_cea_mode(mode); | ||
| 942 | u32 val; | ||
| 943 | |||
| 944 | if (vic == 6 || vic == 7 || vic == 21 || vic == 22 || | ||
| 945 | vic == 2 || vic == 3 || vic == 17 || vic == 18) | ||
| 946 | /* ITU-R BT.601 */ | ||
| 947 | val = 0; | ||
| 948 | else | ||
| 949 | /* ITU-R BT.709 */ | ||
| 950 | val = EDCR_OCYSEL; | ||
| 951 | |||
| 952 | switch (bus_formats) { | ||
| 953 | case MEDIA_BUS_FMT_YUYV8_1X16: | ||
| 954 | /* enable ycbcr output converter */ | ||
| 955 | regmap_write(ldev->regmap, LTDC_EDCR, EDCR_OCYEN | val); | ||
| 956 | break; | ||
| 957 | case MEDIA_BUS_FMT_YVYU8_1X16: | ||
| 958 | /* enable ycbcr output converter & invert chrominance order */ | ||
| 959 | regmap_write(ldev->regmap, LTDC_EDCR, EDCR_OCYEN | EDCR_OCYCO | val); | ||
| 960 | break; | ||
| 961 | default: | ||
| 962 | /* disable ycbcr output converter */ | ||
| 963 | regmap_write(ldev->regmap, LTDC_EDCR, 0); | ||
| 964 | break; | ||
| 965 | } | ||
| 966 | } | ||
| 627 | } | 967 | } |
| 628 | 968 | ||
| 629 | static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, | 969 | static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, |
| @@ -638,7 +978,8 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, · 8 unmodified lines | |||
| 638 | ltdc_crtc_update_clut(crtc); | 978 | ltdc_crtc_update_clut(crtc); |
| 639 | 979 | ||
| 640 | /* Commit shadow registers = update planes at next vblank */ | 980 | /* Commit shadow registers = update planes at next vblank */ |
| 641 | reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); | 981 | if (!ldev->caps.plane_reg_shadow) |
| 982 | regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); | ||
| 642 | 983 | ||
| 643 | if (event) { | 984 | if (event) { |
| 644 | crtc->state->event = NULL; | 985 | crtc->state->event = NULL; |
| @@ -680,10 +1021,14 @@ static bool ltdc_crtc_get_scanout_position(struct drm_crtc *crtc, · 35 unmodified lines | |||
| 680 | * simplify the code and only test if line > vactive_end | 1021 | * simplify the code and only test if line > vactive_end |
| 681 | */ | 1022 | */ |
| 682 | if (pm_runtime_active(ddev->dev)) { | 1023 | if (pm_runtime_active(ddev->dev)) { |
| 683 | line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS; | 1024 | regmap_read(ldev->regmap, LTDC_CPSR, &line); |
| 684 | vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP; | 1025 | line &= CPSR_CYPOS; |
| 685 | vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH; | 1026 | regmap_read(ldev->regmap, LTDC_BPCR, &vactive_start); |
| 686 | vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH; | 1027 | vactive_start &= BPCR_AVBP; |
| 1028 | regmap_read(ldev->regmap, LTDC_AWCR, &vactive_end); | ||
| 1029 | vactive_end &= AWCR_AAH; | ||
| 1030 | regmap_read(ldev->regmap, LTDC_TWCR, &vtotal); | ||
| 1031 | vtotal &= TWCR_TOTALH; | ||
| 687 | 1032 | ||
| 688 | if (line > vactive_end) | 1033 | if (line > vactive_end) |
| 689 | *vpos = line - vtotal - vactive_start; | 1034 | *vpos = line - vtotal - vactive_start; |
| @@ -719,7 +1064,7 @@ static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc) · 29 unmodified lines | |||
| 719 | DRM_DEBUG_DRIVER("\n"); | 1064 | DRM_DEBUG_DRIVER("\n"); |
| 720 | 1065 | ||
| 721 | if (state->enable) | 1066 | if (state->enable) |
| 722 | reg_set(ldev->regs, LTDC_IER, IER_LIE); | 1067 | regmap_set_bits(ldev->regmap, LTDC_IER, IER_LIE); |
| 723 | else | 1068 | else |
| 724 | return -EPERM; | 1069 | return -EPERM; |
| 725 | 1070 | ||
| @@ -731,7 +1076,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) · 5 unmodified lines | |||
| 731 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); | 1076 | struct ltdc_device *ldev = crtc_to_ltdc(crtc); |
| 732 | 1077 | ||
| 733 | DRM_DEBUG_DRIVER("\n"); | 1078 | DRM_DEBUG_DRIVER("\n"); |
| 734 | reg_clear(ldev->regs, LTDC_IER, IER_LIE); | 1079 | regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE); |
| 735 | } | 1080 | } |
| 736 | 1081 | ||
| 737 | static const struct drm_crtc_funcs ltdc_crtc_funcs = { | 1082 | static const struct drm_crtc_funcs ltdc_crtc_funcs = { |
| @@ -789,7 +1134,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 51 unmodified lines | |||
| 789 | u32 y0 = newstate->crtc_y; | 1134 | u32 y0 = newstate->crtc_y; |
| 790 | u32 y1 = newstate->crtc_y + newstate->crtc_h - 1; | 1135 | u32 y1 = newstate->crtc_y + newstate->crtc_h - 1; |
| 791 | u32 src_x, src_y, src_w, src_h; | 1136 | u32 src_x, src_y, src_w, src_h; |
| 792 | u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; | 1137 | u32 val, pitch_in_bytes, line_length, line_number, paddr, ahbp, avbp, bpcr; |
| 793 | enum ltdc_pix_fmt pf; | 1138 | enum ltdc_pix_fmt pf; |
| 794 | 1139 | ||
| 795 | if (!newstate->crtc || !fb) { | 1140 | if (!newstate->crtc || !fb) { |
| @@ -809,19 +1154,20 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 13 unmodified lines | |||
| 809 | newstate->crtc_w, newstate->crtc_h, | 1154 | newstate->crtc_w, newstate->crtc_h, |
| 810 | newstate->crtc_x, newstate->crtc_y); | 1155 | newstate->crtc_x, newstate->crtc_y); |
| 811 | 1156 | ||
| 812 | bpcr = reg_read(ldev->regs, LTDC_BPCR); | 1157 | regmap_read(ldev->regmap, LTDC_BPCR, &bpcr); |
| 1158 | |||
| 813 | ahbp = (bpcr & BPCR_AHBP) >> 16; | 1159 | ahbp = (bpcr & BPCR_AHBP) >> 16; |
| 814 | avbp = bpcr & BPCR_AVBP; | 1160 | avbp = bpcr & BPCR_AVBP; |
| 815 | 1161 | ||
| 816 | /* Configures the horizontal start and stop position */ | 1162 | /* Configures the horizontal start and stop position */ |
| 817 | val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); | 1163 | val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); |
| 818 | reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, | 1164 | regmap_write_bits(ldev->regmap, LTDC_L1WHPCR + lofs, |
| 819 | LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); | 1165 | LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); |
| 820 | 1166 | ||
| 821 | /* Configures the vertical start and stop position */ | 1167 | /* Configures the vertical start and stop position */ |
| 822 | val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); | 1168 | val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); |
| 823 | reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, | 1169 | regmap_write_bits(ldev->regmap, LTDC_L1WVPCR + lofs, |
| 824 | LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); | 1170 | LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); |
| 825 | 1171 | ||
| 826 | /* Specifies the pixel format */ | 1172 | /* Specifies the pixel format */ |
| 827 | pf = to_ltdc_pixelformat(fb->format->format); | 1173 | pf = to_ltdc_pixelformat(fb->format->format); |
| @@ -829,24 +1175,27 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 1 unmodified line | |||
| 829 | if (ldev->caps.pix_fmt_hw[val] == pf) | 1175 | if (ldev->caps.pix_fmt_hw[val] == pf) |
| 830 | break; | 1176 | break; |
| 831 | 1177 | ||
| 1178 | /* Use the flexible color format feature if necessary and available */ | ||
| 1179 | if (ldev->caps.pix_fmt_flex && val == NB_PF) | ||
| 1180 | val = ltdc_set_flexible_pixel_format(plane, pf); | ||
| 1181 | |||
| 832 | if (val == NB_PF) { | 1182 | if (val == NB_PF) { |
| 833 | DRM_ERROR("Pixel format %.4s not supported\n", | 1183 | DRM_ERROR("Pixel format %.4s not supported\n", |
| 834 | (char *)&fb->format->format); | 1184 | (char *)&fb->format->format); |
| 835 | val = 0; /* set by default ARGB 32 bits */ | 1185 | val = 0; /* set by default ARGB 32 bits */ |
| 836 | } | 1186 | } |
| 837 | reg_update_bits(ldev->regs, LTDC_L1PFCR + lofs, LXPFCR_PF, val); | 1187 | regmap_write_bits(ldev->regmap, LTDC_L1PFCR + lofs, LXPFCR_PF, val); |
| 838 | 1188 | ||
| 839 | /* Configures the color frame buffer pitch in bytes & line length */ | 1189 | /* Configures the color frame buffer pitch in bytes & line length */ |
| 840 | pitch_in_bytes = fb->pitches[0]; | 1190 | pitch_in_bytes = fb->pitches[0]; |
| 841 | line_length = fb->format->cpp[0] * | 1191 | line_length = fb->format->cpp[0] * |
| 842 | (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; | 1192 | (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; |
| 843 | val = ((pitch_in_bytes << 16) | line_length); | 1193 | val = ((pitch_in_bytes << 16) | line_length); |
| 844 | reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, | 1194 | regmap_write_bits(ldev->regmap, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); |
| 845 | LXCFBLR_CFBLL | LXCFBLR_CFBP, val); | ||
| 846 | 1195 | ||
| 847 | /* Specifies the constant alpha value */ | 1196 | /* Specifies the constant alpha value */ |
| 848 | val = newstate->alpha >> 8; | 1197 | val = newstate->alpha >> 8; |
| 849 | reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); | 1198 | regmap_write_bits(ldev->regmap, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); |
| 850 | 1199 | ||
| 851 | /* Specifies the blending factors */ | 1200 | /* Specifies the blending factors */ |
| 852 | val = BF1_PAXCA | BF2_1PAXCA; | 1201 | val = BF1_PAXCA | BF2_1PAXCA; |
| @@ -858,24 +1207,98 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, · 5 unmodified lines | |||
| 858 | plane->type != DRM_PLANE_TYPE_PRIMARY) | 1207 | plane->type != DRM_PLANE_TYPE_PRIMARY) |
| 859 | val = BF1_PAXCA | BF2_1PAXCA; | 1208 | val = BF1_PAXCA | BF2_1PAXCA; |
| 860 | 1209 | ||
| 861 | reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, | 1210 | regmap_write_bits(ldev->regmap, LTDC_L1BFCR + lofs, LXBFCR_BF2 | LXBFCR_BF1, val); |
| 862 | LXBFCR_BF2 | LXBFCR_BF1, val); | ||
| 863 | 1211 | ||
| 864 | /* Configures the frame buffer line number */ | 1212 | /* Configures the frame buffer line number */ |
| 865 | val = y1 - y0 + 1; | 1213 | line_number = y1 - y0 + 1; |
| 866 | reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); | 1214 | regmap_write_bits(ldev->regmap, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, line_number); |
| 867 | 1215 | ||
| 868 | /* Sets the FB address */ | 1216 | /* Sets the FB address */ |
| 869 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 0); | 1217 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 0); |
| 870 | 1218 | ||
| 871 | DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); | 1219 | DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); |
| 872 | reg_write(ldev->regs, LTDC_L1CFBAR + lofs, paddr); | 1220 | regmap_write(ldev->regmap, LTDC_L1CFBAR + lofs, paddr); |
| 1221 | |||
| 1222 | if (ldev->caps.ycbcr_input) { | ||
| 1223 | if (fb->format->is_yuv) { | ||
| 1224 | switch (fb->format->format) { | ||
| 1225 | case DRM_FORMAT_NV12: | ||
| 1226 | case DRM_FORMAT_NV21: | ||
| 1227 | /* Configure the auxiliary frame buffer address 0 & 1 */ | ||
| 1228 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); | ||
| 1229 | regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); | ||
| 1230 | regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr + 1); | ||
| 1231 | |||
| 1232 | /* Configure the buffer length */ | ||
| 1233 | val = ((pitch_in_bytes << 16) | line_length); | ||
| 1234 | regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); | ||
| 1235 | |||
| 1236 | /* Configure the frame buffer line number */ | ||
| 1237 | val = (line_number >> 1); | ||
| 1238 | regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); | ||
| 1239 | break; | ||
| 1240 | case DRM_FORMAT_YUV420: | ||
| 1241 | /* Configure the auxiliary frame buffer address 0 */ | ||
| 1242 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); | ||
| 1243 | regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); | ||
| 1244 | |||
| 1245 | /* Configure the auxiliary frame buffer address 1 */ | ||
| 1246 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); | ||
| 1247 | regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr); | ||
| 1248 | |||
| 1249 | line_length = ((fb->format->cpp[0] * (x1 - x0 + 1)) >> 1) + | ||
| 1250 | (ldev->caps.bus_width >> 3) - 1; | ||
| 1251 | |||
| 1252 | /* Configure the buffer length */ | ||
| 1253 | val = (((pitch_in_bytes >> 1) << 16) | line_length); | ||
| 1254 | regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); | ||
| 1255 | |||
| 1256 | /* Configure the frame buffer line number */ | ||
| 1257 | val = (line_number >> 1); | ||
| 1258 | regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); | ||
| 1259 | break; | ||
| 1260 | case DRM_FORMAT_YVU420: | ||
| 1261 | /* Configure the auxiliary frame buffer address 0 */ | ||
| 1262 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); | ||
| 1263 | regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); | ||
| 1264 | |||
| 1265 | /* Configure the auxiliary frame buffer address 1 */ | ||
| 1266 | paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); | ||
| 1267 | regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr); | ||
| 1268 | |||
| 1269 | line_length = ((fb->format->cpp[0] * (x1 - x0 + 1)) >> 1) + | ||
| 1270 | (ldev->caps.bus_width >> 3) - 1; | ||
| 1271 | |||
| 1272 | /* Configure the buffer length */ | ||
| 1273 | val = (((pitch_in_bytes >> 1) << 16) | line_length); | ||
| 1274 | regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); | ||
| 1275 | |||
| 1276 | /* Configure the frame buffer line number */ | ||
| 1277 | val = (line_number >> 1); | ||
| 1278 | regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); | ||
| 1279 | break; | ||
| 1280 | } | ||
| 1281 | |||
| 1282 | /* Configure YCbC conversion coefficient */ | ||
| 1283 | ltdc_set_ycbcr_coeffs(plane); | ||
| 1284 | |||
| 1285 | /* Configure YCbCr format and enable/disable conversion */ | ||
| 1286 | ltdc_set_ycbcr_config(plane, fb->format->format); | ||
| 1287 | } else { | ||
| 1288 | /* disable ycbcr conversion */ | ||
| 1289 | regmap_write(ldev->regmap, LTDC_L1PCR + lofs, 0); | ||
| 1290 | } | ||
| 1291 | } | ||
| 873 | 1292 | ||
| 874 | /* Enable layer and CLUT if needed */ | 1293 | /* Enable layer and CLUT if needed */ |
| 875 | val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0; | 1294 | val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0; |
| 876 | val |= LXCR_LEN; | 1295 | val |= LXCR_LEN; |
| 877 | reg_update_bits(ldev->regs, LTDC_L1CR + lofs, | 1296 | regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN | LXCR_CLUTEN, val); |
| 878 | LXCR_LEN | LXCR_CLUTEN, val); | 1297 | |
| 1298 | /* Commit shadow registers = update plane at next vblank */ | ||
| 1299 | if (ldev->caps.plane_reg_shadow) | ||
| 1300 | regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, | ||
| 1301 | LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); | ||
| 879 | 1302 | ||
| 880 | ldev->plane_fpsi[plane->index].counter++; | 1303 | ldev->plane_fpsi[plane->index].counter++; |
| 881 | 1304 | ||
| @@ -900,7 +1323,12 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane, · 18 unmodified lines | |||
| 900 | u32 lofs = plane->index * LAY_OFS; | 1323 | u32 lofs = plane->index * LAY_OFS; |
| 901 | 1324 | ||
| 902 | /* disable layer */ | 1325 | /* disable layer */ |
| 903 | reg_clear(ldev->regs, LTDC_L1CR + lofs, LXCR_LEN); | 1326 | regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN, 0); |
| 1327 | |||
| 1328 | /* Commit shadow registers = update plane at next vblank */ | ||
| 1329 | if (ldev->caps.plane_reg_shadow) | ||
| 1330 | regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, | ||
| 1331 | LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); | ||
| 904 | 1332 | ||
| 905 | DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", | 1333 | DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", |
| 906 | oldstate->crtc->base.id, plane->base.id); | 1334 | oldstate->crtc->base.id, plane->base.id); |
| @@ -925,16 +1353,6 @@ static void ltdc_plane_atomic_print_state(struct drm_printer *p, · 18 unmodified lines | |||
| 925 | fpsi->counter = 0; | 1353 | fpsi->counter = 0; |
| 926 | } | 1354 | } |
| 927 | 1355 | ||
| 928 | static bool ltdc_plane_format_mod_supported(struct drm_plane *plane, | ||
| 929 | u32 format, | ||
| 930 | u64 modifier) | ||
| 931 | { | ||
| 932 | if (modifier == DRM_FORMAT_MOD_LINEAR) | ||
| 933 | return true; | ||
| 934 | |||
| 935 | return false; | ||
| 936 | } | ||
| 937 | |||
| 938 | static const struct drm_plane_funcs ltdc_plane_funcs = { | 1356 | static const struct drm_plane_funcs ltdc_plane_funcs = { |
| 939 | .update_plane = drm_atomic_helper_update_plane, | 1357 | .update_plane = drm_atomic_helper_update_plane, |
| 940 | .disable_plane = drm_atomic_helper_disable_plane, | 1358 | .disable_plane = drm_atomic_helper_disable_plane, |
| @@ -943,7 +1361,6 @@ static const struct drm_plane_funcs ltdc_plane_funcs = { · 2 unmodified lines | |||
| 943 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, | 1361 | .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, |
| 944 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, | 1362 | .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, |
| 945 | .atomic_print_state = ltdc_plane_atomic_print_state, | 1363 | .atomic_print_state = ltdc_plane_atomic_print_state, |
| 946 | .format_mod_supported = ltdc_plane_format_mod_supported, | ||
| 947 | }; | 1364 | }; |
| 948 | 1365 | ||
| 949 | static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { | 1366 | static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { |
| @@ -953,36 +1370,58 @@ static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { · 3 unmodified lines | |||
| 953 | }; | 1370 | }; |
| 954 | 1371 | ||
| 955 | static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, | 1372 | static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, |
| 956 | enum drm_plane_type type) | 1373 | enum drm_plane_type type, |
| 1374 | int index) | ||
| 957 | { | 1375 | { |
| 958 | unsigned long possible_crtcs = CRTC_MASK; | 1376 | unsigned long possible_crtcs = CRTC_MASK; |
| 959 | struct ltdc_device *ldev = ddev->dev_private; | 1377 | struct ltdc_device *ldev = ddev->dev_private; |
| 960 | struct device *dev = ddev->dev; | 1378 | struct device *dev = ddev->dev; |
| 961 | struct drm_plane *plane; | 1379 | struct drm_plane *plane; |
| 962 | unsigned int i, nb_fmt = 0; | 1380 | unsigned int i, nb_fmt = 0; |
| 963 | u32 formats[NB_PF * 2]; | 1381 | u32 *formats; |
| 964 | u32 drm_fmt, drm_fmt_no_alpha; | 1382 | u32 drm_fmt; |
| 965 | const u64 *modifiers = ltdc_format_modifiers; | 1383 | const u64 *modifiers = ltdc_format_modifiers; |
| 1384 | u32 lofs = index * LAY_OFS; | ||
| 1385 | u32 val; | ||
| 966 | int ret; | 1386 | int ret; |
| 967 | 1387 | ||
| 968 | /* Get supported pixel formats */ | 1388 | /* Allocate the biggest size according to supported color formats */ |
| 969 | for (i = 0; i < NB_PF; i++) { | 1389 | formats = devm_kzalloc(dev, (ldev->caps.pix_fmt_nb + |
| 970 | drm_fmt = to_drm_pixelformat(ldev->caps.pix_fmt_hw[i]); | 1390 | ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp) + |
| 971 | if (!drm_fmt) | 1391 | ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp) + |
| 972 | continue; | 1392 | ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp)) * |
| 973 | formats[nb_fmt++] = drm_fmt; | 1393 | sizeof(*formats), GFP_KERNEL); |
| 974 | 1394 | ||
| 975 | /* Add the no-alpha related format if any & supported */ | 1395 | for (i = 0; i < ldev->caps.pix_fmt_nb; i++) { |
| 976 | drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt); | 1396 | drm_fmt = ldev->caps.pix_fmt_drm[i]; |
| 977 | if (!drm_fmt_no_alpha) | ||
| 978 | continue; | ||
| 979 | 1397 | ||
| 980 | /* Manage hw-specific capabilities */ | 1398 | /* Manage hw-specific capabilities */ |
| 981 | if (ldev->caps.non_alpha_only_l1 && | 1399 | if (ldev->caps.non_alpha_only_l1) |
| 982 | type != DRM_PLANE_TYPE_PRIMARY) | 1400 | /* XR24 & RX24 like formats supported only on primary layer */ |
| 983 | continue; | 1401 | if (type != DRM_PLANE_TYPE_PRIMARY && is_xrgb(drm_fmt)) |
| 1402 | continue; | ||
| 984 | 1403 | ||
| 985 | formats[nb_fmt++] = drm_fmt_no_alpha; | 1404 | formats[nb_fmt++] = drm_fmt; |
| 1405 | } | ||
| 1406 | |||
| 1407 | /* Add YCbCr supported pixel formats */ | ||
| 1408 | if (ldev->caps.ycbcr_input) { | ||
| 1409 | regmap_read(ldev->regmap, LTDC_L1C1R + lofs, &val); | ||
| 1410 | if (val & LXCR_C1R_YIA) { | ||
| 1411 | memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_cp, | ||
| 1412 | ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp) * sizeof(*formats)); | ||
| 1413 | nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp); | ||
| 1414 | } | ||
| 1415 | if (val & LXCR_C1R_YSPA) { | ||
| 1416 | memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_sp, | ||
| 1417 | ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp) * sizeof(*formats)); | ||
| 1418 | nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp); | ||
| 1419 | } | ||
| 1420 | if (val & LXCR_C1R_YFPA) { | ||
| 1421 | memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_fp, | ||
| 1422 | ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp) * sizeof(*formats)); | ||
| 1423 | nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp); | ||
| 1424 | } | ||
| 986 | } | 1425 | } |
| 987 | 1426 | ||
| 988 | plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); | 1427 | plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); |
| @@ -995,6 +1434,17 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, · 6 unmodified lines | |||
| 995 | if (ret < 0) | 1434 | if (ret < 0) |
| 996 | return NULL; | 1435 | return NULL; |
| 997 | 1436 | ||
| 1437 | if (ldev->caps.ycbcr_input) { | ||
| 1438 | if (val & (LXCR_C1R_YIA | LXCR_C1R_YSPA | LXCR_C1R_YFPA)) | ||
| 1439 | drm_plane_create_color_properties(plane, | ||
| 1440 | BIT(DRM_COLOR_YCBCR_BT601) | | ||
| 1441 | BIT(DRM_COLOR_YCBCR_BT709), | ||
| 1442 | BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | | ||
| 1443 | BIT(DRM_COLOR_YCBCR_FULL_RANGE), | ||
| 1444 | DRM_COLOR_YCBCR_BT601, | ||
| 1445 | DRM_COLOR_YCBCR_LIMITED_RANGE); | ||
| 1446 | } | ||
| 1447 | |||
| 998 | drm_plane_helper_add(plane, <dc_plane_helper_funcs); | 1448 | drm_plane_helper_add(plane, <dc_plane_helper_funcs); |
| 999 | 1449 | ||
| 1000 | drm_plane_create_alpha_property(plane); | 1450 | drm_plane_create_alpha_property(plane); |
| @@ -1020,7 +1470,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) · 19 unmodified lines | |||
| 1020 | unsigned int i; | 1470 | unsigned int i; |
| 1021 | int ret; | 1471 | int ret; |
| 1022 | 1472 | ||
| 1023 | primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY); | 1473 | primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY, 0); |
| 1024 | if (!primary) { | 1474 | if (!primary) { |
| 1025 | DRM_ERROR("Can not create primary plane\n"); | 1475 | DRM_ERROR("Can not create primary plane\n"); |
| 1026 | return -EINVAL; | 1476 | return -EINVAL; |
| @@ -1044,7 +1494,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) · 17 unmodified lines | |||
| 1044 | 1494 | ||
| 1045 | /* Add planes. Note : the first layer is used by primary plane */ | 1495 | /* Add planes. Note : the first layer is used by primary plane */ |
| 1046 | for (i = 1; i < ldev->caps.nb_layers; i++) { | 1496 | for (i = 1; i < ldev->caps.nb_layers; i++) { |
| 1047 | overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY); | 1497 | overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i); |
| 1048 | if (!overlay) { | 1498 | if (!overlay) { |
| 1049 | ret = -ENOMEM; | 1499 | ret = -ENOMEM; |
| 1050 | DRM_ERROR("Can not create overlay plane %d\n", i); | 1500 | DRM_ERROR("Can not create overlay plane %d\n", i); |
| @@ -1068,7 +1518,7 @@ static void ltdc_encoder_disable(struct drm_encoder *encoder) · 17 unmodified lines | |||
| 1068 | DRM_DEBUG_DRIVER("\n"); | 1518 | DRM_DEBUG_DRIVER("\n"); |
| 1069 | 1519 | ||
| 1070 | /* Disable LTDC */ | 1520 | /* Disable LTDC */ |
| 1071 | reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); | 1521 | regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); |
| 1072 | 1522 | ||
| 1073 | /* Set to sleep state the pinctrl whatever type of encoder */ | 1523 | /* Set to sleep state the pinctrl whatever type of encoder */ |
| 1074 | pinctrl_pm_select_sleep_state(ddev->dev); | 1524 | pinctrl_pm_select_sleep_state(ddev->dev); |
| @@ -1082,7 +1532,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder) · 7 unmodified lines | |||
| 1082 | DRM_DEBUG_DRIVER("\n"); | 1532 | DRM_DEBUG_DRIVER("\n"); |
| 1083 | 1533 | ||
| 1084 | /* Enable LTDC */ | 1534 | /* Enable LTDC */ |
| 1085 | reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); | 1535 | regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); |
| 1086 | } | 1536 | } |
| 1087 | 1537 | ||
| 1088 | static void ltdc_encoder_mode_set(struct drm_encoder *encoder, | 1538 | static void ltdc_encoder_mode_set(struct drm_encoder *encoder, |
| @@ -1145,21 +1595,25 @@ static int ltdc_get_caps(struct drm_device *ddev) · 56 unmodified lines | |||
| 1145 | * at least 1 layer must be managed & the number of layers | 1595 | * at least 1 layer must be managed & the number of layers |
| 1146 | * must not exceed LTDC_MAX_LAYER | 1596 | * must not exceed LTDC_MAX_LAYER |
| 1147 | */ | 1597 | */ |
| 1148 | lcr = reg_read(ldev->regs, LTDC_LCR); | 1598 | regmap_read(ldev->regmap, LTDC_LCR, &lcr); |
| 1149 | 1599 | ||
| 1150 | ldev->caps.nb_layers = clamp((int)lcr, 1, LTDC_MAX_LAYER); | 1600 | ldev->caps.nb_layers = clamp((int)lcr, 1, LTDC_MAX_LAYER); |
| 1151 | 1601 | ||
| 1152 | /* set data bus width */ | 1602 | /* set data bus width */ |
| 1153 | gc2r = reg_read(ldev->regs, LTDC_GC2R); | 1603 | regmap_read(ldev->regmap, LTDC_GC2R, &gc2r); |
| 1154 | bus_width_log2 = (gc2r & GC2R_BW) >> 4; | 1604 | bus_width_log2 = (gc2r & GC2R_BW) >> 4; |
| 1155 | ldev->caps.bus_width = 8 << bus_width_log2; | 1605 | ldev->caps.bus_width = 8 << bus_width_log2; |
| 1156 | ldev->caps.hw_version = reg_read(ldev->regs, LTDC_IDR); | 1606 | regmap_read(ldev->regmap, LTDC_IDR, &ldev->caps.hw_version); |
| 1157 | 1607 | ||
| 1158 | switch (ldev->caps.hw_version) { | 1608 | switch (ldev->caps.hw_version) { |
| 1159 | case HWVER_10200: | 1609 | case HWVER_10200: |
| 1160 | case HWVER_10300: | 1610 | case HWVER_10300: |
| 1161 | ldev->caps.reg_ofs = REG_OFS_NONE; | 1611 | ldev->caps.layer_ofs = LAY_OFS_0; |
| 1612 | ldev->caps.layer_regs = ltdc_layer_regs_a0; | ||
| 1162 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; | 1613 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; |
| 1614 | ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a0; | ||
| 1615 | ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a0); | ||
| 1616 | ldev->caps.pix_fmt_flex = false; | ||
| 1163 | /* | 1617 | /* |
| 1164 | * Hw older versions support non-alpha color formats derived | 1618 | * Hw older versions support non-alpha color formats derived |
| 1165 | * from native alpha color formats only on the primary layer. | 1619 | * from native alpha color formats only on the primary layer. |
| @@ -1172,13 +1626,37 @@ static int ltdc_get_caps(struct drm_device *ddev) · 6 unmodified lines | |||
| 1172 | if (ldev->caps.hw_version == HWVER_10200) | 1626 | if (ldev->caps.hw_version == HWVER_10200) |
| 1173 | ldev->caps.pad_max_freq_hz = 65000000; | 1627 | ldev->caps.pad_max_freq_hz = 65000000; |
| 1174 | ldev->caps.nb_irq = 2; | 1628 | ldev->caps.nb_irq = 2; |
| 1629 | ldev->caps.ycbcr_input = false; | ||
| 1630 | ldev->caps.ycbcr_output = false; | ||
| 1631 | ldev->caps.plane_reg_shadow = false; | ||
| 1175 | break; | 1632 | break; |
| 1176 | case HWVER_20101: | 1633 | case HWVER_20101: |
| 1177 | ldev->caps.reg_ofs = REG_OFS_4; | 1634 | ldev->caps.layer_ofs = LAY_OFS_0; |
| 1635 | ldev->caps.layer_regs = ltdc_layer_regs_a1; | ||
| 1178 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; | 1636 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; |
| 1637 | ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a1; | ||
| 1638 | ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a1); | ||
| 1639 | ldev->caps.pix_fmt_flex = false; | ||
| 1179 | ldev->caps.non_alpha_only_l1 = false; | 1640 | ldev->caps.non_alpha_only_l1 = false; |
| 1180 | ldev->caps.pad_max_freq_hz = 150000000; | 1641 | ldev->caps.pad_max_freq_hz = 150000000; |
| 1181 | ldev->caps.nb_irq = 4; | 1642 | ldev->caps.nb_irq = 4; |
| 1643 | ldev->caps.ycbcr_input = false; | ||
| 1644 | ldev->caps.ycbcr_output = false; | ||
| 1645 | ldev->caps.plane_reg_shadow = false; | ||
| 1646 | break; | ||
| 1647 | case HWVER_40100: | ||
| 1648 | ldev->caps.layer_ofs = LAY_OFS_1; | ||
| 1649 | ldev->caps.layer_regs = ltdc_layer_regs_a2; | ||
| 1650 | ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a2; | ||
| 1651 | ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a2; | ||
| 1652 | ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a2); | ||
| 1653 | ldev->caps.pix_fmt_flex = true; | ||
| 1654 | ldev->caps.non_alpha_only_l1 = false; | ||
| 1655 | ldev->caps.pad_max_freq_hz = 90000000; | ||
| 1656 | ldev->caps.nb_irq = 2; | ||
| 1657 | ldev->caps.ycbcr_input = true; | ||
| 1658 | ldev->caps.ycbcr_output = true; | ||
| 1659 | ldev->caps.plane_reg_shadow = true; | ||
| 1182 | break; | 1660 | break; |
| 1183 | default: | 1661 | default: |
| 1184 | return -ENODEV; | 1662 | return -ENODEV; |
| @@ -1296,9 +1774,15 @@ int ltdc_load(struct drm_device *ddev) · 111 unmodified lines | |||
| 1296 | goto err; | 1774 | goto err; |
| 1297 | } | 1775 | } |
| 1298 | 1776 | ||
| 1777 | ldev->regmap = devm_regmap_init_mmio(&pdev->dev, ldev->regs, &stm32_ltdc_regmap_cfg); | ||
| 1778 | if (IS_ERR(ldev->regmap)) { | ||
| 1779 | DRM_ERROR("Unable to regmap ltdc registers\n"); | ||
| 1780 | ret = PTR_ERR(ldev->regmap); | ||
| 1781 | goto err; | ||
| 1782 | } | ||
| 1783 | |||
| 1299 | /* Disable interrupts */ | 1784 | /* Disable interrupts */ |
| 1300 | reg_clear(ldev->regs, LTDC_IER, | 1785 | regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); |
| 1301 | IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); | ||
| 1302 | 1786 | ||
| 1303 | ret = ltdc_get_caps(ddev); | 1787 | ret = ltdc_get_caps(ddev); |
| 1304 | if (ret) { | 1788 | if (ret) { |
| @@ -14,12 +14,19 @@ · 13 unmodified lines | |||
| 14 | struct ltdc_caps { | 14 | struct ltdc_caps { |
| 15 | u32 hw_version; /* hardware version */ | 15 | u32 hw_version; /* hardware version */ |
| 16 | u32 nb_layers; /* number of supported layers */ | 16 | u32 nb_layers; /* number of supported layers */ |
| 17 | u32 reg_ofs; /* register offset for applicable regs */ | 17 | u32 layer_ofs; /* layer offset for applicable regs */ |
| 18 | const u32 *layer_regs; /* layer register offset */ | ||
| 18 | u32 bus_width; /* bus width (32 or 64 bits) */ | 19 | u32 bus_width; /* bus width (32 or 64 bits) */ |
| 19 | const u32 *pix_fmt_hw; /* supported pixel formats */ | 20 | const u32 *pix_fmt_hw; /* supported hw pixel formats */ |
| 21 | const u32 *pix_fmt_drm; /* supported drm pixel formats */ | ||
| 22 | int pix_fmt_nb; /* number of pixel format */ | ||
| 23 | bool pix_fmt_flex; /* pixel format flexibility supported */ | ||
| 20 | bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ | 24 | bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ |
| 21 | int pad_max_freq_hz; /* max frequency supported by pad */ | 25 | int pad_max_freq_hz; /* max frequency supported by pad */ |
| 22 | int nb_irq; /* number of hardware interrupts */ | 26 | int nb_irq; /* number of hardware interrupts */ |
| 27 | bool ycbcr_input; /* ycbcr input converter supported */ | ||
| 28 | bool ycbcr_output; /* ycbcr output converter supported */ | ||
| 29 | bool plane_reg_shadow; /* plane shadow registers ability */ | ||
| 23 | }; | 30 | }; |
| 24 | 31 | ||
| 25 | #define LTDC_MAX_LAYER 4 | 32 | #define LTDC_MAX_LAYER 4 |
| @@ -31,6 +38,7 @@ struct fps_info { · 5 unmodified lines | |||
| 31 | 38 | ||
| 32 | struct ltdc_device { | 39 | struct ltdc_device { |
| 33 | void __iomem *regs; | 40 | void __iomem *regs; |
| 41 | struct regmap *regmap; | ||
| 34 | struct clk *pixel_clk; /* lcd pixel clock */ | 42 | struct clk *pixel_clk; /* lcd pixel clock */ |
| 35 | struct mutex err_lock; /* protecting error_status */ | 43 | struct mutex err_lock; /* protecting error_status */ |
| 36 | struct ltdc_caps caps; | 44 | struct ltdc_caps caps; |
| @@ -5,6 +5,7 @@ config DRM_TEGRA · 4 unmodified lines | |||
| 5 | depends on COMMON_CLK | 5 | depends on COMMON_CLK |
| 6 | depends on DRM | 6 | depends on DRM |
| 7 | depends on OF | 7 | depends on OF |
| 8 | select DRM_DP_HELPER | ||
| 8 | select DRM_KMS_HELPER | 9 | select DRM_KMS_HELPER |
| 9 | select DRM_MIPI_DSI | 10 | select DRM_MIPI_DSI |
| 10 | select DRM_PANEL | 11 | select DRM_PANEL |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | |||
| 5 | */ | 5 | */ |
| 6 | 6 | ||
| 7 | #include <drm/drm_crtc.h> | 7 | #include <drm/drm_crtc.h> |
| 8 | #include <drm/drm_dp_helper.h> | 8 | #include <drm/dp/drm_dp_helper.h> |
| 9 | #include <drm/drm_print.h> | 9 | #include <drm/drm_print.h> |
| 10 | 10 | ||
| 11 | #include "dp.h" | 11 | #include "dp.h" |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include <linux/reset.h> | 18 | #include <linux/reset.h> |
| 19 | #include <linux/workqueue.h> | 19 | #include <linux/workqueue.h> |
| 20 | 20 | ||
| 21 | #include <drm/drm_dp_helper.h> | 21 | #include <drm/dp/drm_dp_helper.h> |
| 22 | #include <drm/drm_panel.h> | 22 | #include <drm/drm_panel.h> |
| 23 | 23 | ||
| 24 | #include "dp.h" | 24 | #include "dp.h" |
| @@ -18,7 +18,7 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | #include <drm/drm_atomic_helper.h> | 19 | #include <drm/drm_atomic_helper.h> |
| 20 | #include <drm/drm_debugfs.h> | 20 | #include <drm/drm_debugfs.h> |
| 21 | #include <drm/drm_dp_helper.h> | 21 | #include <drm/dp/drm_dp_helper.h> |
| 22 | #include <drm/drm_file.h> | 22 | #include <drm/drm_file.h> |
| 23 | #include <drm/drm_panel.h> | 23 | #include <drm/drm_panel.h> |
| 24 | #include <drm/drm_scdc_helper.h> | 24 | #include <drm/drm_scdc_helper.h> |
| @@ -60,8 +60,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) · 59 unmodified lines | |||
| 60 | list_del(&mod->list); | 60 | list_del(&mod->list); |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | static struct of_device_id tilcdc_of_match[]; | ||
| 64 | |||
| 65 | static int tilcdc_atomic_check(struct drm_device *dev, | 63 | static int tilcdc_atomic_check(struct drm_device *dev, |
| 66 | struct drm_atomic_state *state) | 64 | struct drm_atomic_state *state) |
| 67 | { | 65 | { |
| @@ -587,7 +585,7 @@ static int tilcdc_pdev_remove(struct platform_device *pdev) · 519 unmodified lines | |||
| 587 | return 0; | 585 | return 0; |
| 588 | } | 586 | } |
| 589 | 587 | ||
| 590 | static struct of_device_id tilcdc_of_match[] = { | 588 | static const struct of_device_id tilcdc_of_match[] = { |
| 591 | { .compatible = "ti,am33xx-tilcdc", }, | 589 | { .compatible = "ti,am33xx-tilcdc", }, |
| 592 | { .compatible = "ti,da850-tilcdc", }, | 590 | { .compatible = "ti,da850-tilcdc", }, |
| 593 | { }, | 591 | { }, |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <drm/drm_gem_framebuffer_helper.h> | 10 | #include <drm/drm_gem_framebuffer_helper.h> |
| 11 | #include <drm/drm_gem_vram_helper.h> | 11 | #include <drm/drm_gem_vram_helper.h> |
| 12 | #include <drm/drm_managed.h> | 12 | #include <drm/drm_managed.h> |
| 13 | #include <drm/drm_module.h> | ||
| 13 | #include <drm/drm_probe_helper.h> | 14 | #include <drm/drm_probe_helper.h> |
| 14 | #include <drm/drm_simple_kms_helper.h> | 15 | #include <drm/drm_simple_kms_helper.h> |
| 15 | 16 | ||
| @@ -716,24 +717,7 @@ static struct pci_driver bochs_pci_driver = { · 700 unmodified lines | |||
| 716 | /* ---------------------------------------------------------------------- */ | 717 | /* ---------------------------------------------------------------------- */ |
| 717 | /* module init/exit */ | 718 | /* module init/exit */ |
| 718 | 719 | ||
| 719 | static int __init bochs_init(void) | 720 | drm_module_pci_driver_if_modeset(bochs_pci_driver, bochs_modeset); |
| 720 | { | ||
| 721 | if (drm_firmware_drivers_only() && bochs_modeset == -1) | ||
| 722 | return -EINVAL; | ||
| 723 | |||
| 724 | if (bochs_modeset == 0) | ||
| 725 | return -EINVAL; | ||
| 726 | |||
| 727 | return pci_register_driver(&bochs_pci_driver); | ||
| 728 | } | ||
| 729 | |||
| 730 | static void __exit bochs_exit(void) | ||
| 731 | { | ||
| 732 | pci_unregister_driver(&bochs_pci_driver); | ||
| 733 | } | ||
| 734 | |||
| 735 | module_init(bochs_init); | ||
| 736 | module_exit(bochs_exit); | ||
| 737 | 721 | ||
| 738 | MODULE_DEVICE_TABLE(pci, bochs_pci_tbl); | 722 | MODULE_DEVICE_TABLE(pci, bochs_pci_tbl); |
| 739 | MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); | 723 | MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>"); |
| @@ -39,6 +39,7 @@ · 38 unmodified lines | |||
| 39 | #include <drm/drm_ioctl.h> | 39 | #include <drm/drm_ioctl.h> |
| 40 | #include <drm/drm_managed.h> | 40 | #include <drm/drm_managed.h> |
| 41 | #include <drm/drm_modeset_helper_vtables.h> | 41 | #include <drm/drm_modeset_helper_vtables.h> |
| 42 | #include <drm/drm_module.h> | ||
| 42 | #include <drm/drm_probe_helper.h> | 43 | #include <drm/drm_probe_helper.h> |
| 43 | #include <drm/drm_simple_kms_helper.h> | 44 | #include <drm/drm_simple_kms_helper.h> |
| 44 | 45 | ||
| @@ -633,21 +634,7 @@ static struct pci_driver cirrus_pci_driver = { · 588 unmodified lines | |||
| 633 | .remove = cirrus_pci_remove, | 634 | .remove = cirrus_pci_remove, |
| 634 | }; | 635 | }; |
| 635 | 636 | ||
| 636 | static int __init cirrus_init(void) | 637 | drm_module_pci_driver(cirrus_pci_driver) |
| 637 | { | ||
| 638 | if (drm_firmware_drivers_only()) | ||
| 639 | return -EINVAL; | ||
| 640 | |||
| 641 | return pci_register_driver(&cirrus_pci_driver); | ||
| 642 | } | ||
| 643 | |||
| 644 | static void __exit cirrus_exit(void) | ||
| 645 | { | ||
| 646 | pci_unregister_driver(&cirrus_pci_driver); | ||
| 647 | } | ||
| 648 | |||
| 649 | module_init(cirrus_init); | ||
| 650 | module_exit(cirrus_exit); | ||
| 651 | 638 | ||
| 652 | MODULE_DEVICE_TABLE(pci, pciidlist); | 639 | MODULE_DEVICE_TABLE(pci, pciidlist); |
| 653 | MODULE_LICENSE("GPL"); | 640 | MODULE_LICENSE("GPL"); |
| @@ -526,21 +526,33 @@ static int simpledrm_device_init_mm(struct simpledrm_device *sdev) · 525 unmodified lines | |||
| 526 | { | 526 | { |
| 527 | struct drm_device *dev = &sdev->dev; | 527 | struct drm_device *dev = &sdev->dev; |
| 528 | struct platform_device *pdev = sdev->pdev; | 528 | struct platform_device *pdev = sdev->pdev; |
| 529 | struct resource *mem; | 529 | struct resource *res, *mem; |
| 530 | void __iomem *screen_base; | 530 | void __iomem *screen_base; |
| 531 | int ret; | 531 | int ret; |
| 532 | 532 | ||
| 533 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 533 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 534 | if (!mem) | 534 | if (!res) |
| 535 | return -EINVAL; | 535 | return -EINVAL; |
| 536 | 536 | ||
| 537 | ret = devm_aperture_acquire_from_firmware(dev, mem->start, resource_size(mem)); | 537 | ret = devm_aperture_acquire_from_firmware(dev, res->start, resource_size(res)); |
| 538 | if (ret) { | 538 | if (ret) { |
| 539 | drm_err(dev, "could not acquire memory range %pr: error %d\n", | 539 | drm_err(dev, "could not acquire memory range %pr: error %d\n", |
| 540 | mem, ret); | 540 | res, ret); |
| 541 | return ret; | 541 | return ret; |
| 542 | } | 542 | } |
| 543 | 543 | ||
| 544 | mem = devm_request_mem_region(&pdev->dev, res->start, resource_size(res), | ||
| 545 | sdev->dev.driver->name); | ||
| 546 | if (!mem) { | ||
| 547 | /* | ||
| 548 | * We cannot make this fatal. Sometimes this comes from magic | ||
| 549 | * spaces our resource handlers simply don't know about. Use | ||
| 550 | * the I/O-memory resource as-is and try to map that instead. | ||
| 551 | */ | ||
| 552 | drm_warn(dev, "could not acquire memory region %pr\n", res); | ||
| 553 | mem = res; | ||
| 554 | } | ||
| 555 | |||
| 544 | screen_base = devm_ioremap_wc(&pdev->dev, mem->start, | 556 | screen_base = devm_ioremap_wc(&pdev->dev, mem->start, |
| 545 | resource_size(mem)); | 557 | resource_size(mem)); |
| 546 | if (!screen_base) | 558 | if (!screen_base) |
| @@ -241,6 +241,11 @@ static int ttm_buffer_object_transfer(struct ttm_buffer_object *bo, · 240 unmodified lines | |||
| 241 | if (bo->type != ttm_bo_type_sg) | 241 | if (bo->type != ttm_bo_type_sg) |
| 242 | fbo->base.base.resv = &fbo->base.base._resv; | 242 | fbo->base.base.resv = &fbo->base.base._resv; |
| 243 | 243 | ||
| 244 | if (fbo->base.resource) { | ||
| 245 | ttm_resource_set_bo(fbo->base.resource, &fbo->base); | ||
| 246 | bo->resource = NULL; | ||
| 247 | } | ||
| 248 | |||
| 244 | dma_resv_init(&fbo->base.base._resv); | 249 | dma_resv_init(&fbo->base.base._resv); |
| 245 | fbo->base.base.dev = NULL; | 250 | fbo->base.base.dev = NULL; |
| 246 | ret = dma_resv_trylock(&fbo->base.base._resv); | 251 | ret = dma_resv_trylock(&fbo->base.base._resv); |
| @@ -509,7 +514,6 @@ static int ttm_bo_move_to_ghost(struct ttm_buffer_object *bo, · 262 unmodified lines | |||
| 509 | ghost_obj->ttm = NULL; | 514 | ghost_obj->ttm = NULL; |
| 510 | else | 515 | else |
| 511 | bo->ttm = NULL; | 516 | bo->ttm = NULL; |
| 512 | bo->resource = NULL; | ||
| 513 | 517 | ||
| 514 | dma_resv_unlock(&ghost_obj->base._resv); | 518 | dma_resv_unlock(&ghost_obj->base._resv); |
| 515 | ttm_bo_put(ghost_obj); | 519 | ttm_bo_put(ghost_obj); |
| @@ -637,7 +641,6 @@ int ttm_bo_pipeline_gutting(struct ttm_buffer_object *bo) · 121 unmodified lines | |||
| 637 | dma_resv_unlock(&ghost->base._resv); | 641 | dma_resv_unlock(&ghost->base._resv); |
| 638 | ttm_bo_put(ghost); | 642 | ttm_bo_put(ghost); |
| 639 | bo->ttm = ttm; | 643 | bo->ttm = ttm; |
| 640 | bo->resource = NULL; | ||
| 641 | ttm_bo_assign_mem(bo, sys_res); | 644 | ttm_bo_assign_mem(bo, sys_res); |
| 642 | return 0; | 645 | return 0; |
| 643 | 646 | ||
| @@ -89,6 +89,7 @@ static int ttm_range_man_alloc(struct ttm_resource_manager *man, · 88 unmodified lines | |||
| 89 | spin_unlock(&rman->lock); | 89 | spin_unlock(&rman->lock); |
| 90 | 90 | ||
| 91 | if (unlikely(ret)) { | 91 | if (unlikely(ret)) { |
| 92 | ttm_resource_fini(man, *res); | ||
| 92 | kfree(node); | 93 | kfree(node); |
| 93 | return ret; | 94 | return ret; |
| 94 | } | 95 | } |
| @@ -108,6 +109,7 @@ static void ttm_range_man_free(struct ttm_resource_manager *man, · 13 unmodified lines | |||
| 108 | drm_mm_remove_node(&node->mm_nodes[0]); | 109 | drm_mm_remove_node(&node->mm_nodes[0]); |
| 109 | spin_unlock(&rman->lock); | 110 | spin_unlock(&rman->lock); |
| 110 | 111 | ||
| 112 | ttm_resource_fini(man, res); | ||
| 111 | kfree(node); | 113 | kfree(node); |
| 112 | } | 114 | } |
| 113 | 115 | ||
| @@ -156,7 +158,7 @@ int ttm_range_man_init_nocheck(struct ttm_device *bdev, · 42 unmodified lines | |||
| 156 | 158 | ||
| 157 | man->func = &ttm_range_manager_func; | 159 | man->func = &ttm_range_manager_func; |
| 158 | 160 | ||
| 159 | ttm_resource_manager_init(man, p_size); | 161 | ttm_resource_manager_init(man, bdev, p_size); |
| 160 | 162 | ||
| 161 | drm_mm_init(&rman->mm, 0, p_size); | 163 | drm_mm_init(&rman->mm, 0, p_size); |
| 162 | spin_lock_init(&rman->lock); | 164 | spin_lock_init(&rman->lock); |
| @@ -29,6 +29,14 @@ · 28 unmodified lines | |||
| 29 | #include <drm/ttm/ttm_resource.h> | 29 | #include <drm/ttm/ttm_resource.h> |
| 30 | #include <drm/ttm/ttm_bo_driver.h> | 30 | #include <drm/ttm/ttm_bo_driver.h> |
| 31 | 31 | ||
| 32 | /** | ||
| 33 | * ttm_resource_init - resource object constructure | ||
| 34 | * @bo: buffer object this resources is allocated for | ||
| 35 | * @place: placement of the resource | ||
| 36 | * @res: the resource object to inistilize | ||
| 37 | * | ||
| 38 | * Initialize a new resource object. Counterpart of &ttm_resource_fini. | ||
| 39 | */ | ||
| 32 | void ttm_resource_init(struct ttm_buffer_object *bo, | 40 | void ttm_resource_init(struct ttm_buffer_object *bo, |
| 33 | const struct ttm_place *place, | 41 | const struct ttm_place *place, |
| 34 | struct ttm_resource *res) | 42 | struct ttm_resource *res) |
| @@ -41,9 +49,25 @@ void ttm_resource_init(struct ttm_buffer_object *bo, · 6 unmodified lines | |||
| 41 | res->bus.offset = 0; | 49 | res->bus.offset = 0; |
| 42 | res->bus.is_iomem = false; | 50 | res->bus.is_iomem = false; |
| 43 | res->bus.caching = ttm_cached; | 51 | res->bus.caching = ttm_cached; |
| 52 | res->bo = bo; | ||
| 44 | } | 53 | } |
| 45 | EXPORT_SYMBOL(ttm_resource_init); | 54 | EXPORT_SYMBOL(ttm_resource_init); |
| 46 | 55 | ||
| 56 | /** | ||
| 57 | * ttm_resource_fini - resource destructor | ||
| 58 | * @man: the resource manager this resource belongs to | ||
| 59 | * @res: the resource to clean up | ||
| 60 | * | ||
| 61 | * Should be used by resource manager backends to clean up the TTM resource | ||
| 62 | * objects before freeing the underlying structure. Counterpart of | ||
| 63 | * &ttm_resource_init | ||
| 64 | */ | ||
| 65 | void ttm_resource_fini(struct ttm_resource_manager *man, | ||
| 66 | struct ttm_resource *res) | ||
| 67 | { | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL(ttm_resource_fini); | ||
| 70 | |||
| 47 | int ttm_resource_alloc(struct ttm_buffer_object *bo, | 71 | int ttm_resource_alloc(struct ttm_buffer_object *bo, |
| 48 | const struct ttm_place *place, | 72 | const struct ttm_place *place, |
| 49 | struct ttm_resource **res_ptr) | 73 | struct ttm_resource **res_ptr) |
| @@ -116,20 +140,31 @@ bool ttm_resource_compat(struct ttm_resource *res, · 66 unmodified lines | |||
| 116 | } | 140 | } |
| 117 | EXPORT_SYMBOL(ttm_resource_compat); | 141 | EXPORT_SYMBOL(ttm_resource_compat); |
| 118 | 142 | ||
| 143 | void ttm_resource_set_bo(struct ttm_resource *res, | ||
| 144 | struct ttm_buffer_object *bo) | ||
| 145 | { | ||
| 146 | spin_lock(&bo->bdev->lru_lock); | ||
| 147 | res->bo = bo; | ||
| 148 | spin_unlock(&bo->bdev->lru_lock); | ||
| 149 | } | ||
| 150 | |||
| 119 | /** | 151 | /** |
| 120 | * ttm_resource_manager_init | 152 | * ttm_resource_manager_init |
| 121 | * | 153 | * |
| 122 | * @man: memory manager object to init | 154 | * @man: memory manager object to init |
| 155 | * @bdev: ttm device this manager belongs to | ||
| 123 | * @p_size: size managed area in pages. | 156 | * @p_size: size managed area in pages. |
| 124 | * | 157 | * |
| 125 | * Initialise core parts of a manager object. | 158 | * Initialise core parts of a manager object. |
| 126 | */ | 159 | */ |
| 127 | void ttm_resource_manager_init(struct ttm_resource_manager *man, | 160 | void ttm_resource_manager_init(struct ttm_resource_manager *man, |
| 161 | struct ttm_device *bdev, | ||
| 128 | unsigned long p_size) | 162 | unsigned long p_size) |
| 129 | { | 163 | { |
| 130 | unsigned i; | 164 | unsigned i; |
| 131 | 165 | ||
| 132 | spin_lock_init(&man->move_lock); | 166 | spin_lock_init(&man->move_lock); |
| 167 | man->bdev = bdev; | ||
| 133 | man->size = p_size; | 168 | man->size = p_size; |
| 134 | 169 | ||
| 135 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) | 170 | for (i = 0; i < TTM_MAX_BO_PRIORITY; ++i) |
| @@ -23,6 +23,7 @@ static int ttm_sys_man_alloc(struct ttm_resource_manager *man, · 22 unmodified lines | |||
| 23 | static void ttm_sys_man_free(struct ttm_resource_manager *man, | 23 | static void ttm_sys_man_free(struct ttm_resource_manager *man, |
| 24 | struct ttm_resource *res) | 24 | struct ttm_resource *res) |
| 25 | { | 25 | { |
| 26 | ttm_resource_fini(man, res); | ||
| 26 | kfree(res); | 27 | kfree(res); |
| 27 | } | 28 | } |
| 28 | 29 | ||
| @@ -42,7 +43,7 @@ void ttm_sys_man_init(struct ttm_device *bdev) · 13 unmodified lines | |||
| 42 | man->use_tt = true; | 43 | man->use_tt = true; |
| 43 | man->func = &ttm_sys_manager_func; | 44 | man->func = &ttm_sys_manager_func; |
| 44 | 45 | ||
| 45 | ttm_resource_manager_init(man, 0); | 46 | ttm_resource_manager_init(man, bdev, 0); |
| 46 | ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); | 47 | ttm_set_driver_manager(bdev, TTM_PL_SYSTEM, man); |
| 47 | ttm_resource_manager_set_used(man, true); | 48 | ttm_resource_manager_set_used(man, true); |
| 48 | } | 49 | } |
| @@ -219,6 +219,7 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) · 218 unmodified lines | |||
| 219 | int ret; | 219 | int ret; |
| 220 | u32 mmu_debug; | 220 | u32 mmu_debug; |
| 221 | u32 ident1; | 221 | u32 ident1; |
| 222 | u64 mask; | ||
| 222 | 223 | ||
| 223 | v3d = devm_drm_dev_alloc(dev, &v3d_drm_driver, struct v3d_dev, drm); | 224 | v3d = devm_drm_dev_alloc(dev, &v3d_drm_driver, struct v3d_dev, drm); |
| 224 | if (IS_ERR(v3d)) | 225 | if (IS_ERR(v3d)) |
| @@ -237,8 +238,11 @@ static int v3d_platform_drm_probe(struct platform_device *pdev) · 12 unmodified lines | |||
| 237 | return ret; | 238 | return ret; |
| 238 | 239 | ||
| 239 | mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); | 240 | mmu_debug = V3D_READ(V3D_MMU_DEBUG_INFO); |
| 240 | dma_set_mask_and_coherent(dev, | 241 | mask = DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH)); |
| 241 | DMA_BIT_MASK(30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_PA_WIDTH))); | 242 | ret = dma_set_mask_and_coherent(dev, mask); |
| 243 | if (ret) | ||
| 244 | return ret; | ||
| 245 | |||
| 242 | v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); | 246 | v3d->va_width = 30 + V3D_GET_FIELD(mmu_debug, V3D_MMU_VA_WIDTH); |
| 243 | 247 | ||
| 244 | ident1 = V3D_READ(V3D_HUB_IDENT1); | 248 | ident1 = V3D_READ(V3D_HUB_IDENT1); |
| @@ -355,8 +355,6 @@ static struct vc4_bo *vc4_bo_get_from_cache(struct drm_device *dev, · 354 unmodified lines | |||
| 355 | uint32_t page_index = bo_page_index(size); | 355 | uint32_t page_index = bo_page_index(size); |
| 356 | struct vc4_bo *bo = NULL; | 356 | struct vc4_bo *bo = NULL; |
| 357 | 357 | ||
| 358 | size = roundup(size, PAGE_SIZE); | ||
| 359 | |||
| 360 | mutex_lock(&vc4->bo_lock); | 358 | mutex_lock(&vc4->bo_lock); |
| 361 | if (page_index >= vc4->bo_cache.size_list_size) | 359 | if (page_index >= vc4->bo_cache.size_list_size) |
| 362 | goto out; | 360 | goto out; |
| @@ -37,6 +37,8 @@ · 36 unmodified lines | |||
| 37 | #include <drm/drm_fb_helper.h> | 37 | #include <drm/drm_fb_helper.h> |
| 38 | #include <drm/drm_vblank.h> | 38 | #include <drm/drm_vblank.h> |
| 39 | 39 | ||
| 40 | #include <soc/bcm2835/raspberrypi-firmware.h> | ||
| 41 | |||
| 40 | #include "uapi/drm/vc4_drm.h" | 42 | #include "uapi/drm/vc4_drm.h" |
| 41 | 43 | ||
| 42 | #include "vc4_drv.h" | 44 | #include "vc4_drv.h" |
| @@ -215,6 +217,7 @@ static void vc4_match_add_drivers(struct device *dev, · 172 unmodified lines | |||
| 215 | static int vc4_drm_bind(struct device *dev) | 217 | static int vc4_drm_bind(struct device *dev) |
| 216 | { | 218 | { |
| 217 | struct platform_device *pdev = to_platform_device(dev); | 219 | struct platform_device *pdev = to_platform_device(dev); |
| 220 | struct rpi_firmware *firmware = NULL; | ||
| 218 | struct drm_device *drm; | 221 | struct drm_device *drm; |
| 219 | struct vc4_dev *vc4; | 222 | struct vc4_dev *vc4; |
| 220 | struct device_node *node; | 223 | struct device_node *node; |
| @@ -251,15 +254,34 @@ static int vc4_drm_bind(struct device *dev) · 30 unmodified lines | |||
| 251 | if (ret) | 254 | if (ret) |
| 252 | return ret; | 255 | return ret; |
| 253 | 256 | ||
| 254 | ret = component_bind_all(dev, drm); | 257 | node = of_find_compatible_node(NULL, NULL, "raspberrypi,bcm2835-firmware"); |
| 258 | if (node) { | ||
| 259 | firmware = rpi_firmware_get(node); | ||
| 260 | of_node_put(node); | ||
| 261 | |||
| 262 | if (!firmware) | ||
| 263 | return -EPROBE_DEFER; | ||
| 264 | } | ||
| 265 | |||
| 266 | ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver); | ||
| 255 | if (ret) | 267 | if (ret) |
| 256 | return ret; | 268 | return ret; |
| 257 | 269 | ||
| 258 | ret = vc4_plane_create_additional_planes(drm); | 270 | if (firmware) { |
| 271 | ret = rpi_firmware_property(firmware, | ||
| 272 | RPI_FIRMWARE_NOTIFY_DISPLAY_DONE, | ||
| 273 | NULL, 0); | ||
| 274 | if (ret) | ||
| 275 | drm_warn(drm, "Couldn't stop firmware display driver: %d\n", ret); | ||
| 276 | |||
| 277 | rpi_firmware_put(firmware); | ||
| 278 | } | ||
| 279 | |||
| 280 | ret = component_bind_all(dev, drm); | ||
| 259 | if (ret) | 281 | if (ret) |
| 260 | goto unbind_all; | 282 | return ret; |
| 261 | 283 | ||
| 262 | ret = drm_aperture_remove_framebuffers(false, &vc4_drm_driver); | 284 | ret = vc4_plane_create_additional_planes(drm); |
| 263 | if (ret) | 285 | if (ret) |
| 264 | goto unbind_all; | 286 | goto unbind_all; |
| 265 | 287 | ||
| @@ -357,6 +379,9 @@ static int __init vc4_drm_register(void) · 91 unmodified lines | |||
| 357 | { | 379 | { |
| 358 | int ret; | 380 | int ret; |
| 359 | 381 | ||
| 382 | if (drm_firmware_drivers_only()) | ||
| 383 | return -ENODEV; | ||
| 384 | |||
| 360 | ret = platform_register_drivers(component_drivers, | 385 | ret = platform_register_drivers(component_drivers, |
| 361 | ARRAY_SIZE(component_drivers)); | 386 | ARRAY_SIZE(component_drivers)); |
| 362 | if (ret) | 387 | if (ret) |
| @@ -104,6 +104,15 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode) · 103 unmodified lines | |||
| 104 | return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; | 104 | return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | static bool vc4_hdmi_is_full_range_rgb(struct vc4_hdmi *vc4_hdmi, | ||
| 108 | const struct drm_display_mode *mode) | ||
| 109 | { | ||
| 110 | struct vc4_hdmi_encoder *vc4_encoder = &vc4_hdmi->encoder; | ||
| 111 | |||
| 112 | return !vc4_encoder->hdmi_monitor || | ||
| 113 | drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_FULL; | ||
| 114 | } | ||
| 115 | |||
| 107 | static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) | 116 | static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) |
| 108 | { | 117 | { |
| 109 | struct drm_info_node *node = (struct drm_info_node *)m->private; | 118 | struct drm_info_node *node = (struct drm_info_node *)m->private; |
| @@ -481,7 +490,6 @@ static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder, · 371 unmodified lines | |||
| 481 | static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) | 490 | static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) |
| 482 | { | 491 | { |
| 483 | struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); | 492 | struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); |
| 484 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | ||
| 485 | struct drm_connector *connector = &vc4_hdmi->connector; | 493 | struct drm_connector *connector = &vc4_hdmi->connector; |
| 486 | struct drm_connector_state *cstate = connector->state; | 494 | struct drm_connector_state *cstate = connector->state; |
| 487 | const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; | 495 | const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; |
| @@ -499,10 +507,10 @@ static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder) · 11 unmodified lines | |||
| 499 | 507 | ||
| 500 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, | 508 | drm_hdmi_avi_infoframe_quant_range(&frame.avi, |
| 501 | connector, mode, | 509 | connector, mode, |
| 502 | vc4_encoder->limited_rgb_range ? | 510 | vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode) ? |
| 503 | HDMI_QUANTIZATION_RANGE_LIMITED : | 511 | HDMI_QUANTIZATION_RANGE_FULL : |
| 504 | HDMI_QUANTIZATION_RANGE_FULL); | 512 | HDMI_QUANTIZATION_RANGE_LIMITED); |
| 505 | drm_hdmi_avi_infoframe_colorspace(&frame.avi, cstate); | 513 | drm_hdmi_avi_infoframe_colorimetry(&frame.avi, cstate); |
| 506 | drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); | 514 | drm_hdmi_avi_infoframe_bars(&frame.avi, cstate); |
| 507 | 515 | ||
| 508 | vc4_hdmi_write_infoframe(encoder, &frame); | 516 | vc4_hdmi_write_infoframe(encoder, &frame); |
| @@ -726,7 +734,9 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder) · 217 unmodified lines | |||
| 726 | mutex_unlock(&vc4_hdmi->mutex); | 734 | mutex_unlock(&vc4_hdmi->mutex); |
| 727 | } | 735 | } |
| 728 | 736 | ||
| 729 | static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) | 737 | static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, |
| 738 | struct drm_connector_state *state, | ||
| 739 | const struct drm_display_mode *mode) | ||
| 730 | { | 740 | { |
| 731 | unsigned long flags; | 741 | unsigned long flags; |
| 732 | u32 csc_ctl; | 742 | u32 csc_ctl; |
| @@ -736,7 +746,7 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) · 3 unmodified lines | |||
| 736 | csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, | 746 | csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR, |
| 737 | VC4_HD_CSC_CTL_ORDER); | 747 | VC4_HD_CSC_CTL_ORDER); |
| 738 | 748 | ||
| 739 | if (enable) { | 749 | if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) { |
| 740 | /* CEA VICs other than #1 requre limited range RGB | 750 | /* CEA VICs other than #1 requre limited range RGB |
| 741 | * output unless overridden by an AVI infoframe. | 751 | * output unless overridden by an AVI infoframe. |
| 742 | * Apply a colorspace conversion to squash 0-255 down | 752 | * Apply a colorspace conversion to squash 0-255 down |
| @@ -766,44 +776,67 @@ static void vc4_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) · 23 unmodified lines | |||
| 766 | spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); | 776 | spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags); |
| 767 | } | 777 | } |
| 768 | 778 | ||
| 769 | static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, bool enable) | 779 | /* |
| 780 | * If we need to output Full Range RGB, then use the unity matrix | ||
| 781 | * | ||
| 782 | * [ 1 0 0 0] | ||
| 783 | * [ 0 1 0 0] | ||
| 784 | * [ 0 0 1 0] | ||
| 785 | * | ||
| 786 | * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | ||
| 787 | */ | ||
| 788 | static const u16 vc5_hdmi_csc_full_rgb_unity[3][4] = { | ||
| 789 | { 0x2000, 0x0000, 0x0000, 0x0000 }, | ||
| 790 | { 0x0000, 0x2000, 0x0000, 0x0000 }, | ||
| 791 | { 0x0000, 0x0000, 0x2000, 0x0000 }, | ||
| 792 | }; | ||
| 793 | |||
| 794 | /* | ||
| 795 | * CEA VICs other than #1 require limited range RGB output unless | ||
| 796 | * overridden by an AVI infoframe. Apply a colorspace conversion to | ||
| 797 | * squash 0-255 down to 16-235. The matrix here is: | ||
| 798 | * | ||
| 799 | * [ 0.8594 0 0 16] | ||
| 800 | * [ 0 0.8594 0 16] | ||
| 801 | * [ 0 0 0.8594 16] | ||
| 802 | * | ||
| 803 | * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | ||
| 804 | */ | ||
| 805 | static const u16 vc5_hdmi_csc_full_rgb_to_limited_rgb[3][4] = { | ||
| 806 | { 0x1b80, 0x0000, 0x0000, 0x0400 }, | ||
| 807 | { 0x0000, 0x1b80, 0x0000, 0x0400 }, | ||
| 808 | { 0x0000, 0x0000, 0x1b80, 0x0400 }, | ||
| 809 | }; | ||
| 810 | |||
| 811 | static void vc5_hdmi_set_csc_coeffs(struct vc4_hdmi *vc4_hdmi, | ||
| 812 | const u16 coeffs[3][4]) | ||
| 770 | { | 813 | { |
| 771 | unsigned long flags; | 814 | lockdep_assert_held(&vc4_hdmi->hw_lock); |
| 772 | u32 csc_ctl; | 815 | |
| 816 | HDMI_WRITE(HDMI_CSC_12_11, (coeffs[0][1] << 16) | coeffs[0][0]); | ||
| 817 | HDMI_WRITE(HDMI_CSC_14_13, (coeffs[0][3] << 16) | coeffs[0][2]); | ||
| 818 | HDMI_WRITE(HDMI_CSC_22_21, (coeffs[1][1] << 16) | coeffs[1][0]); | ||
| 819 | HDMI_WRITE(HDMI_CSC_24_23, (coeffs[1][3] << 16) | coeffs[1][2]); | ||
| 820 | HDMI_WRITE(HDMI_CSC_32_31, (coeffs[2][1] << 16) | coeffs[2][0]); | ||
| 821 | HDMI_WRITE(HDMI_CSC_34_33, (coeffs[2][3] << 16) | coeffs[2][2]); | ||
| 822 | } | ||
| 773 | 823 | ||
| 774 | csc_ctl = 0x07; /* RGB_CONVERT_MODE = custom matrix, || USE_RGB_TO_YCBCR */ | 824 | static void vc5_hdmi_csc_setup(struct vc4_hdmi *vc4_hdmi, |
| 825 | struct drm_connector_state *state, | ||
| 826 | const struct drm_display_mode *mode) | ||
| 827 | { | ||
| 828 | unsigned long flags; | ||
| 829 | u32 csc_ctl = VC5_MT_CP_CSC_CTL_ENABLE | VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM, | ||
| 830 | VC5_MT_CP_CSC_CTL_MODE); | ||
| 775 | 831 | ||
| 776 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); | 832 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
| 777 | 833 | ||
| 778 | if (enable) { | 834 | HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); |
| 779 | /* CEA VICs other than #1 requre limited range RGB | 835 | |
| 780 | * output unless overridden by an AVI infoframe. | 836 | if (!vc4_hdmi_is_full_range_rgb(vc4_hdmi, mode)) |
| 781 | * Apply a colorspace conversion to squash 0-255 down | 837 | vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_to_limited_rgb); |
| 782 | * to 16-235. The matrix here is: | 838 | else |
| 783 | * | 839 | vc5_hdmi_set_csc_coeffs(vc4_hdmi, vc5_hdmi_csc_full_rgb_unity); |
| 784 | * [ 0.8594 0 0 16] | ||
| 785 | * [ 0 0.8594 0 16] | ||
| 786 | * [ 0 0 0.8594 16] | ||
| 787 | * [ 0 0 0 1] | ||
| 788 | * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | ||
| 789 | */ | ||
| 790 | HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x1b80); | ||
| 791 | HDMI_WRITE(HDMI_CSC_14_13, (0x0400 << 16) | 0x0000); | ||
| 792 | HDMI_WRITE(HDMI_CSC_22_21, (0x1b80 << 16) | 0x0000); | ||
| 793 | HDMI_WRITE(HDMI_CSC_24_23, (0x0400 << 16) | 0x0000); | ||
| 794 | HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); | ||
| 795 | HDMI_WRITE(HDMI_CSC_34_33, (0x0400 << 16) | 0x1b80); | ||
| 796 | } else { | ||
| 797 | /* Still use the matrix for full range, but make it unity. | ||
| 798 | * Matrix is signed 2p13 fixed point, with signed 9p6 offsets | ||
| 799 | */ | ||
| 800 | HDMI_WRITE(HDMI_CSC_12_11, (0x0000 << 16) | 0x2000); | ||
| 801 | HDMI_WRITE(HDMI_CSC_14_13, (0x0000 << 16) | 0x0000); | ||
| 802 | HDMI_WRITE(HDMI_CSC_22_21, (0x2000 << 16) | 0x0000); | ||
| 803 | HDMI_WRITE(HDMI_CSC_24_23, (0x0000 << 16) | 0x0000); | ||
| 804 | HDMI_WRITE(HDMI_CSC_32_31, (0x0000 << 16) | 0x0000); | ||
| 805 | HDMI_WRITE(HDMI_CSC_34_33, (0x0000 << 16) | 0x2000); | ||
| 806 | } | ||
| 807 | 840 | ||
| 808 | HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); | 841 | HDMI_WRITE(HDMI_CSC_CTL, csc_ctl); |
| 809 | 842 | ||
| @@ -889,7 +922,6 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi, · 79 unmodified lines | |||
| 889 | 922 | ||
| 890 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); | 923 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
| 891 | 924 | ||
| 892 | HDMI_WRITE(HDMI_VEC_INTERFACE_XBAR, 0x354021); | ||
| 893 | HDMI_WRITE(HDMI_HORZA, | 925 | HDMI_WRITE(HDMI_HORZA, |
| 894 | (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | | 926 | (vsync_pos ? VC5_HDMI_HORZA_VPOS : 0) | |
| 895 | (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | | 927 | (hsync_pos ? VC5_HDMI_HORZA_HPOS : 0) | |
| @@ -1113,24 +1145,16 @@ static void vc4_hdmi_encoder_pre_crtc_enable(struct drm_encoder *encoder, · 217 unmodified lines | |||
| 1113 | struct drm_atomic_state *state) | 1145 | struct drm_atomic_state *state) |
| 1114 | { | 1146 | { |
| 1115 | struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); | 1147 | struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); |
| 1148 | struct drm_connector *connector = &vc4_hdmi->connector; | ||
| 1116 | struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; | 1149 | struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode; |
| 1117 | struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); | 1150 | struct drm_connector_state *conn_state = |
| 1151 | drm_atomic_get_new_connector_state(state, connector); | ||
| 1118 | unsigned long flags; | 1152 | unsigned long flags; |
| 1119 | 1153 | ||
| 1120 | mutex_lock(&vc4_hdmi->mutex); | 1154 | mutex_lock(&vc4_hdmi->mutex); |
| 1121 | 1155 | ||
| 1122 | if (vc4_encoder->hdmi_monitor && | 1156 | if (vc4_hdmi->variant->csc_setup) |
| 1123 | drm_default_rgb_quant_range(mode) == HDMI_QUANTIZATION_RANGE_LIMITED) { | 1157 | vc4_hdmi->variant->csc_setup(vc4_hdmi, conn_state, mode); |
| 1124 | if (vc4_hdmi->variant->csc_setup) | ||
| 1125 | vc4_hdmi->variant->csc_setup(vc4_hdmi, true); | ||
| 1126 | |||
| 1127 | vc4_encoder->limited_rgb_range = true; | ||
| 1128 | } else { | ||
| 1129 | if (vc4_hdmi->variant->csc_setup) | ||
| 1130 | vc4_hdmi->variant->csc_setup(vc4_hdmi, false); | ||
| 1131 | |||
| 1132 | vc4_encoder->limited_rgb_range = false; | ||
| 1133 | } | ||
| 1134 | 1158 | ||
| 1135 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); | 1159 | spin_lock_irqsave(&vc4_hdmi->hw_lock, flags); |
| 1136 | HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); | 1160 | HDMI_WRITE(HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N); |
| @@ -12,7 +12,6 @@ · 11 unmodified lines | |||
| 12 | struct vc4_hdmi_encoder { | 12 | struct vc4_hdmi_encoder { |
| 13 | struct vc4_encoder base; | 13 | struct vc4_encoder base; |
| 14 | bool hdmi_monitor; | 14 | bool hdmi_monitor; |
| 15 | bool limited_rgb_range; | ||
| 16 | }; | 15 | }; |
| 17 | 16 | ||
| 18 | static inline struct vc4_hdmi_encoder * | 17 | static inline struct vc4_hdmi_encoder * |
| @@ -77,7 +76,9 @@ struct vc4_hdmi_variant { · 58 unmodified lines | |||
| 77 | void (*reset)(struct vc4_hdmi *vc4_hdmi); | 76 | void (*reset)(struct vc4_hdmi *vc4_hdmi); |
| 78 | 77 | ||
| 79 | /* Callback to enable / disable the CSC */ | 78 | /* Callback to enable / disable the CSC */ |
| 80 | void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, bool enable); | 79 | void (*csc_setup)(struct vc4_hdmi *vc4_hdmi, |
| 80 | struct drm_connector_state *state, | ||
| 81 | const struct drm_display_mode *mode); | ||
| 81 | 82 | ||
| 82 | /* Callback to configure the video timings in the HDMI block */ | 83 | /* Callback to configure the video timings in the HDMI block */ |
| 83 | void (*set_timings)(struct vc4_hdmi *vc4_hdmi, | 84 | void (*set_timings)(struct vc4_hdmi *vc4_hdmi, |
| @@ -774,6 +774,9 @@ enum { · 773 unmodified lines | |||
| 774 | # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) | 774 | # define VC4_HD_CSC_CTL_RGB2YCC BIT(1) |
| 775 | # define VC4_HD_CSC_CTL_ENABLE BIT(0) | 775 | # define VC4_HD_CSC_CTL_ENABLE BIT(0) |
| 776 | 776 | ||
| 777 | # define VC5_MT_CP_CSC_CTL_ENABLE BIT(2) | ||
| 778 | # define VC5_MT_CP_CSC_CTL_MODE_MASK VC4_MASK(1, 0) | ||
| 779 | |||
| 777 | # define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1) | 780 | # define VC4_DVP_HT_CLOCK_STOP_PIXEL BIT(1) |
| 778 | 781 | ||
| 779 | /* HVS display list information. */ | 782 | /* HVS display list information. */ |
| @@ -248,6 +248,9 @@ void virtio_gpu_array_put_free(struct virtio_gpu_object_array *objs) · 247 unmodified lines | |||
| 248 | { | 248 | { |
| 249 | u32 i; | 249 | u32 i; |
| 250 | 250 | ||
| 251 | if (!objs) | ||
| 252 | return; | ||
| 253 | |||
| 251 | for (i = 0; i < objs->nents; i++) | 254 | for (i = 0; i < objs->nents; i++) |
| 252 | drm_gem_object_put(objs->objs[i]); | 255 | drm_gem_object_put(objs->objs[i]); |
| 253 | virtio_gpu_array_free(objs); | 256 | virtio_gpu_array_free(objs); |
| @@ -20,6 +20,8 @@ · 19 unmodified lines | |||
| 20 | #define XRES_MAX 8192 | 20 | #define XRES_MAX 8192 |
| 21 | #define YRES_MAX 8192 | 21 | #define YRES_MAX 8192 |
| 22 | 22 | ||
| 23 | #define NUM_OVERLAY_PLANES 8 | ||
| 24 | |||
| 23 | struct vkms_writeback_job { | 25 | struct vkms_writeback_job { |
| 24 | struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; | 26 | struct dma_buf_map map[DRM_FORMAT_MAX_PLANES]; |
| 25 | struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; | 27 | struct dma_buf_map data[DRM_FORMAT_MAX_PLANES]; |
| @@ -32,6 +32,21 @@ static const struct drm_connector_helper_funcs vkms_conn_helper_funcs = { · 31 unmodified lines | |||
| 32 | .get_modes = vkms_conn_get_modes, | 32 | .get_modes = vkms_conn_get_modes, |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | static int vkms_add_overlay_plane(struct vkms_device *vkmsdev, int index, | ||
| 36 | struct drm_crtc *crtc) | ||
| 37 | { | ||
| 38 | struct vkms_plane *overlay; | ||
| 39 | |||
| 40 | overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); | ||
| 41 | if (IS_ERR(overlay)) | ||
| 42 | return PTR_ERR(overlay); | ||
| 43 | |||
| 44 | if (!overlay->base.possible_crtcs) | ||
| 45 | overlay->base.possible_crtcs = drm_crtc_mask(crtc); | ||
| 46 | |||
| 47 | return 0; | ||
| 48 | } | ||
| 49 | |||
| 35 | int vkms_output_init(struct vkms_device *vkmsdev, int index) | 50 | int vkms_output_init(struct vkms_device *vkmsdev, int index) |
| 36 | { | 51 | { |
| 37 | struct vkms_output *output = &vkmsdev->output; | 52 | struct vkms_output *output = &vkmsdev->output; |
| @@ -39,21 +54,21 @@ int vkms_output_init(struct vkms_device *vkmsdev, int index) · 1 unmodified line | |||
| 39 | struct drm_connector *connector = &output->connector; | 54 | struct drm_connector *connector = &output->connector; |
| 40 | struct drm_encoder *encoder = &output->encoder; | 55 | struct drm_encoder *encoder = &output->encoder; |
| 41 | struct drm_crtc *crtc = &output->crtc; | 56 | struct drm_crtc *crtc = &output->crtc; |
| 42 | struct vkms_plane *primary, *cursor = NULL, *overlay = NULL; | 57 | struct vkms_plane *primary, *cursor = NULL; |
| 43 | int ret; | 58 | int ret; |
| 44 | int writeback; | 59 | int writeback; |
| 60 | unsigned int n; | ||
| 45 | 61 | ||
| 46 | primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); | 62 | primary = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_PRIMARY, index); |
| 47 | if (IS_ERR(primary)) | 63 | if (IS_ERR(primary)) |
| 48 | return PTR_ERR(primary); | 64 | return PTR_ERR(primary); |
| 49 | 65 | ||
| 50 | if (vkmsdev->config->overlay) { | 66 | if (vkmsdev->config->overlay) { |
| 51 | overlay = vkms_plane_init(vkmsdev, DRM_PLANE_TYPE_OVERLAY, index); | 67 | for (n = 0; n < NUM_OVERLAY_PLANES; n++) { |
| 52 | if (IS_ERR(overlay)) | 68 | ret = vkms_add_overlay_plane(vkmsdev, index, crtc); |
| 53 | return PTR_ERR(overlay); | 69 | if (ret) |
| 54 | 70 | return ret; | |
| 55 | if (!overlay->base.possible_crtcs) | 71 | } |
| 56 | overlay->base.possible_crtcs = drm_crtc_mask(crtc); | ||
| 57 | } | 72 | } |
| 58 | 73 | ||
| 59 | if (vkmsdev->config->cursor) { | 74 | if (vkmsdev->config->cursor) { |
| @@ -117,6 +117,7 @@ nospace: · 116 unmodified lines | |||
| 117 | gman->used_gmr_pages -= (*res)->num_pages; | 117 | gman->used_gmr_pages -= (*res)->num_pages; |
| 118 | spin_unlock(&gman->lock); | 118 | spin_unlock(&gman->lock); |
| 119 | ida_free(&gman->gmr_ida, id); | 119 | ida_free(&gman->gmr_ida, id); |
| 120 | ttm_resource_fini(man, *res); | ||
| 120 | kfree(*res); | 121 | kfree(*res); |
| 121 | return -ENOSPC; | 122 | return -ENOSPC; |
| 122 | } | 123 | } |
| @@ -130,6 +131,7 @@ static void vmw_gmrid_man_put_node(struct ttm_resource_manager *man, · 7 unmodified lines | |||
| 130 | spin_lock(&gman->lock); | 131 | spin_lock(&gman->lock); |
| 131 | gman->used_gmr_pages -= res->num_pages; | 132 | gman->used_gmr_pages -= res->num_pages; |
| 132 | spin_unlock(&gman->lock); | 133 | spin_unlock(&gman->lock); |
| 134 | ttm_resource_fini(man, res); | ||
| 133 | kfree(res); | 135 | kfree(res); |
| 134 | } | 136 | } |
| 135 | 137 | ||
| @@ -160,7 +162,7 @@ int vmw_gmrid_man_init(struct vmw_private *dev_priv, int type) · 24 unmodified lines | |||
| 160 | 162 | ||
| 161 | man->func = &vmw_gmrid_manager_func; | 163 | man->func = &vmw_gmrid_manager_func; |
| 162 | man->use_tt = true; | 164 | man->use_tt = true; |
| 163 | ttm_resource_manager_init(man, 0); | 165 | ttm_resource_manager_init(man, &dev_priv->bdev, 0); |
| 164 | spin_lock_init(&gman->lock); | 166 | spin_lock_init(&gman->lock); |
| 165 | gman->used_gmr_pages = 0; | 167 | gman->used_gmr_pages = 0; |
| 166 | ida_init(&gman->gmr_ida); | 168 | ida_init(&gman->gmr_ida); |
| @@ -49,6 +49,7 @@ static int vmw_sys_man_alloc(struct ttm_resource_manager *man, · 48 unmodified lines | |||
| 49 | static void vmw_sys_man_free(struct ttm_resource_manager *man, | 49 | static void vmw_sys_man_free(struct ttm_resource_manager *man, |
| 50 | struct ttm_resource *res) | 50 | struct ttm_resource *res) |
| 51 | { | 51 | { |
| 52 | ttm_resource_fini(man, res); | ||
| 52 | kfree(res); | 53 | kfree(res); |
| 53 | } | 54 | } |
| 54 | 55 | ||
| @@ -69,7 +70,7 @@ int vmw_sys_man_init(struct vmw_private *dev_priv) · 14 unmodified lines | |||
| 69 | man->use_tt = true; | 70 | man->use_tt = true; |
| 70 | man->func = &vmw_sys_manager_func; | 71 | man->func = &vmw_sys_manager_func; |
| 71 | 72 | ||
| 72 | ttm_resource_manager_init(man, 0); | 73 | ttm_resource_manager_init(man, bdev, 0); |
| 73 | ttm_set_driver_manager(bdev, VMW_PL_SYSTEM, man); | 74 | ttm_set_driver_manager(bdev, VMW_PL_SYSTEM, man); |
| 74 | ttm_resource_manager_set_used(man, true); | 75 | ttm_resource_manager_set_used(man, true); |
| 75 | return 0; | 76 | return 0; |
| @@ -6,6 +6,7 @@ config DRM_ZYNQMP_DPSUB · 5 unmodified lines | |||
| 6 | depends on PHY_XILINX_ZYNQMP | 6 | depends on PHY_XILINX_ZYNQMP |
| 7 | depends on XILINX_ZYNQMP_DPDMA | 7 | depends on XILINX_ZYNQMP_DPDMA |
| 8 | select DMA_ENGINE | 8 | select DMA_ENGINE |
| 9 | select DRM_DP_HELPER | ||
| 9 | select DRM_GEM_CMA_HELPER | 10 | select DRM_GEM_CMA_HELPER |
| 10 | select DRM_KMS_HELPER | 11 | select DRM_KMS_HELPER |
| 11 | select GENERIC_PHY | 12 | select GENERIC_PHY |
| @@ -13,7 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include <drm/drm_connector.h> | 13 | #include <drm/drm_connector.h> |
| 14 | #include <drm/drm_crtc.h> | 14 | #include <drm/drm_crtc.h> |
| 15 | #include <drm/drm_device.h> | 15 | #include <drm/drm_device.h> |
| 16 | #include <drm/drm_dp_helper.h> | 16 | #include <drm/dp/drm_dp_helper.h> |
| 17 | #include <drm/drm_edid.h> | 17 | #include <drm/drm_edid.h> |
| 18 | #include <drm/drm_encoder.h> | 18 | #include <drm/drm_encoder.h> |
| 19 | #include <drm/drm_managed.h> | 19 | #include <drm/drm_managed.h> |
| @@ -243,6 +243,17 @@ config CROS_USBPD_NOTIFY · 242 unmodified lines | |||
| 243 | To compile this driver as a module, choose M here: the | 243 | To compile this driver as a module, choose M here: the |
| 244 | module will be called cros_usbpd_notify. | 244 | module will be called cros_usbpd_notify. |
| 245 | 245 | ||
| 246 | config CHROMEOS_PRIVACY_SCREEN | ||
| 247 | tristate "ChromeOS Privacy Screen support" | ||
| 248 | depends on ACPI | ||
| 249 | depends on DRM | ||
| 250 | select DRM_PRIVACY_SCREEN | ||
| 251 | help | ||
| 252 | This driver provides the support needed for the in-built electronic | ||
| 253 | privacy screen that is present on some ChromeOS devices. When enabled, | ||
| 254 | this should probably always be built into the kernel to avoid or | ||
| 255 | minimize drm probe deferral. | ||
| 256 | |||
| 246 | source "drivers/platform/chrome/wilco_ec/Kconfig" | 257 | source "drivers/platform/chrome/wilco_ec/Kconfig" |
| 247 | 258 | ||
| 248 | endif # CHROMEOS_PLATFORMS | 259 | endif # CHROMEOS_PLATFORMS |
| @@ -4,6 +4,7 @@ · 3 unmodified lines | |||
| 4 | CFLAGS_cros_ec_trace.o:= -I$(src) | 4 | CFLAGS_cros_ec_trace.o:= -I$(src) |
| 5 | 5 | ||
| 6 | obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o | 6 | obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o |
| 7 | obj-$(CONFIG_CHROMEOS_PRIVACY_SCREEN) += chromeos_privacy_screen.o | ||
| 7 | obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o | 8 | obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o |
| 8 | obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o | 9 | obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o |
| 9 | obj-$(CONFIG_CROS_EC) += cros_ec.o | 10 | obj-$(CONFIG_CROS_EC) += cros_ec.o |
| @@ -0,0 +1,153 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | /* | ||
| 4 | * ChromeOS Privacy Screen support | ||
| 5 | * | ||
| 6 | * Copyright (C) 2022 Google LLC | ||
| 7 | * | ||
| 8 | * This is the Chromeos privacy screen provider, present on certain chromebooks, | ||
| 9 | * represented by a GOOG0010 device in the ACPI. This ACPI device, if present, | ||
| 10 | * will cause the i915 drm driver to probe defer until this driver registers | ||
| 11 | * the privacy-screen. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/acpi.h> | ||
| 15 | #include <drm/drm_privacy_screen_driver.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * The DSM (Device Specific Method) constants below are the agreed API with | ||
| 19 | * the firmware team, on how to control privacy screen using ACPI methods. | ||
| 20 | */ | ||
| 21 | #define PRIV_SCRN_DSM_REVID 1 /* DSM version */ | ||
| 22 | #define PRIV_SCRN_DSM_FN_GET_STATUS 1 /* Get privacy screen status */ | ||
| 23 | #define PRIV_SCRN_DSM_FN_ENABLE 2 /* Enable privacy screen */ | ||
| 24 | #define PRIV_SCRN_DSM_FN_DISABLE 3 /* Disable privacy screen */ | ||
| 25 | |||
| 26 | static const guid_t chromeos_privacy_screen_dsm_guid = | ||
| 27 | GUID_INIT(0xc7033113, 0x8720, 0x4ceb, | ||
| 28 | 0x90, 0x90, 0x9d, 0x52, 0xb3, 0xe5, 0x2d, 0x73); | ||
| 29 | |||
| 30 | static void | ||
| 31 | chromeos_privacy_screen_get_hw_state(struct drm_privacy_screen | ||
| 32 | *drm_privacy_screen) | ||
| 33 | { | ||
| 34 | union acpi_object *obj; | ||
| 35 | acpi_handle handle; | ||
| 36 | struct device *privacy_screen = | ||
| 37 | drm_privacy_screen_get_drvdata(drm_privacy_screen); | ||
| 38 | |||
| 39 | handle = acpi_device_handle(to_acpi_device(privacy_screen)); | ||
| 40 | obj = acpi_evaluate_dsm(handle, &chromeos_privacy_screen_dsm_guid, | ||
| 41 | PRIV_SCRN_DSM_REVID, | ||
| 42 | PRIV_SCRN_DSM_FN_GET_STATUS, NULL); | ||
| 43 | if (!obj) { | ||
| 44 | dev_err(privacy_screen, | ||
| 45 | "_DSM failed to get privacy-screen state\n"); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | if (obj->type != ACPI_TYPE_INTEGER) | ||
| 50 | dev_err(privacy_screen, | ||
| 51 | "Bad _DSM to get privacy-screen state\n"); | ||
| 52 | else if (obj->integer.value == 1) | ||
| 53 | drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = | ||
| 54 | PRIVACY_SCREEN_ENABLED; | ||
| 55 | else | ||
| 56 | drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = | ||
| 57 | PRIVACY_SCREEN_DISABLED; | ||
| 58 | |||
| 59 | ACPI_FREE(obj); | ||
| 60 | } | ||
| 61 | |||
| 62 | static int | ||
| 63 | chromeos_privacy_screen_set_sw_state(struct drm_privacy_screen | ||
| 64 | *drm_privacy_screen, | ||
| 65 | enum drm_privacy_screen_status state) | ||
| 66 | { | ||
| 67 | union acpi_object *obj = NULL; | ||
| 68 | acpi_handle handle; | ||
| 69 | struct device *privacy_screen = | ||
| 70 | drm_privacy_screen_get_drvdata(drm_privacy_screen); | ||
| 71 | |||
| 72 | handle = acpi_device_handle(to_acpi_device(privacy_screen)); | ||
| 73 | |||
| 74 | if (state == PRIVACY_SCREEN_DISABLED) { | ||
| 75 | obj = acpi_evaluate_dsm(handle, | ||
| 76 | &chromeos_privacy_screen_dsm_guid, | ||
| 77 | PRIV_SCRN_DSM_REVID, | ||
| 78 | PRIV_SCRN_DSM_FN_DISABLE, NULL); | ||
| 79 | } else if (state == PRIVACY_SCREEN_ENABLED) { | ||
| 80 | obj = acpi_evaluate_dsm(handle, | ||
| 81 | &chromeos_privacy_screen_dsm_guid, | ||
| 82 | PRIV_SCRN_DSM_REVID, | ||
| 83 | PRIV_SCRN_DSM_FN_ENABLE, NULL); | ||
| 84 | } else { | ||
| 85 | dev_err(privacy_screen, | ||
| 86 | "Bad attempt to set privacy-screen status to %u\n", | ||
| 87 | state); | ||
| 88 | return -EINVAL; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (!obj) { | ||
| 92 | dev_err(privacy_screen, | ||
| 93 | "_DSM failed to set privacy-screen state\n"); | ||
| 94 | return -EIO; | ||
| 95 | } | ||
| 96 | |||
| 97 | drm_privacy_screen->hw_state = drm_privacy_screen->sw_state = state; | ||
| 98 | ACPI_FREE(obj); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static const struct drm_privacy_screen_ops chromeos_privacy_screen_ops = { | ||
| 103 | .get_hw_state = chromeos_privacy_screen_get_hw_state, | ||
| 104 | .set_sw_state = chromeos_privacy_screen_set_sw_state, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static int chromeos_privacy_screen_add(struct acpi_device *adev) | ||
| 108 | { | ||
| 109 | struct drm_privacy_screen *drm_privacy_screen = | ||
| 110 | drm_privacy_screen_register(&adev->dev, | ||
| 111 | &chromeos_privacy_screen_ops, | ||
| 112 | &adev->dev); | ||
| 113 | |||
| 114 | if (IS_ERR(drm_privacy_screen)) { | ||
| 115 | dev_err(&adev->dev, "Error registering privacy-screen\n"); | ||
| 116 | return PTR_ERR(drm_privacy_screen); | ||
| 117 | } | ||
| 118 | |||
| 119 | adev->driver_data = drm_privacy_screen; | ||
| 120 | dev_info(&adev->dev, "registered privacy-screen '%s'\n", | ||
| 121 | dev_name(&drm_privacy_screen->dev)); | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static int chromeos_privacy_screen_remove(struct acpi_device *adev) | ||
| 127 | { | ||
| 128 | struct drm_privacy_screen *drm_privacy_screen = acpi_driver_data(adev); | ||
| 129 | |||
| 130 | drm_privacy_screen_unregister(drm_privacy_screen); | ||
| 131 | return 0; | ||
| 132 | } | ||
| 133 | |||
| 134 | static const struct acpi_device_id chromeos_privacy_screen_device_ids[] = { | ||
| 135 | {"GOOG0010", 0}, /* Google's electronic privacy screen for eDP-1 */ | ||
| 136 | {} | ||
| 137 | }; | ||
| 138 | MODULE_DEVICE_TABLE(acpi, chromeos_privacy_screen_device_ids); | ||
| 139 | |||
| 140 | static struct acpi_driver chromeos_privacy_screen_driver = { | ||
| 141 | .name = "chromeos_privacy_screen_driver", | ||
| 142 | .class = "ChromeOS", | ||
| 143 | .ids = chromeos_privacy_screen_device_ids, | ||
| 144 | .ops = { | ||
| 145 | .add = chromeos_privacy_screen_add, | ||
| 146 | .remove = chromeos_privacy_screen_remove, | ||
| 147 | }, | ||
| 148 | }; | ||
| 149 | |||
| 150 | module_acpi_driver(chromeos_privacy_screen_driver); | ||
| 151 | MODULE_LICENSE("GPL v2"); | ||
| 152 | MODULE_DESCRIPTION("ChromeOS ACPI Privacy Screen driver"); | ||
| 153 | MODULE_AUTHOR("Rajat Jain <rajatja@google.com>"); | ||
| @@ -9869,7 +9869,7 @@ static int tpacpi_lcdshadow_init(struct ibm_init_struct *iibm) · 9868 unmodified lines | |||
| 9869 | return 0; | 9869 | return 0; |
| 9870 | 9870 | ||
| 9871 | lcdshadow_dev = drm_privacy_screen_register(&tpacpi_pdev->dev, | 9871 | lcdshadow_dev = drm_privacy_screen_register(&tpacpi_pdev->dev, |
| 9872 | &lcdshadow_ops); | 9872 | &lcdshadow_ops, NULL); |
| 9873 | if (IS_ERR(lcdshadow_dev)) | 9873 | if (IS_ERR(lcdshadow_dev)) |
| 9874 | return PTR_ERR(lcdshadow_dev); | 9874 | return PTR_ERR(lcdshadow_dev); |
| 9875 | 9875 | ||
| @@ -110,7 +110,7 @@ static const struct fb_ops asiliantfb_ops = { · 109 unmodified lines | |||
| 110 | static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div) | 110 | static void asiliant_calc_dclk2(u32 *ppixclock, u8 *dclk2_m, u8 *dclk2_n, u8 *dclk2_div) |
| 111 | { | 111 | { |
| 112 | unsigned pixclock = *ppixclock; | 112 | unsigned pixclock = *ppixclock; |
| 113 | unsigned Ftarget = 1000000 * (1000000 / pixclock); | 113 | unsigned Ftarget; |
| 114 | unsigned n; | 114 | unsigned n; |
| 115 | unsigned best_error = 0xffffffff; | 115 | unsigned best_error = 0xffffffff; |
| 116 | unsigned best_m = 0xffffffff, | 116 | unsigned best_m = 0xffffffff, |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
| 26 | #include <linux/linux_logo.h> | 26 | #include <linux/linux_logo.h> |
| 27 | #include <linux/proc_fs.h> | 27 | #include <linux/proc_fs.h> |
| 28 | #include <linux/platform_device.h> | ||
| 28 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
| 29 | #include <linux/console.h> | 30 | #include <linux/console.h> |
| 30 | #include <linux/kmod.h> | 31 | #include <linux/kmod.h> |
| @@ -1557,18 +1558,36 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a, · 1526 unmodified lines | |||
| 1557 | /* check all firmware fbs and kick off if the base addr overlaps */ | 1558 | /* check all firmware fbs and kick off if the base addr overlaps */ |
| 1558 | for_each_registered_fb(i) { | 1559 | for_each_registered_fb(i) { |
| 1559 | struct apertures_struct *gen_aper; | 1560 | struct apertures_struct *gen_aper; |
| 1561 | struct device *device; | ||
| 1560 | 1562 | ||
| 1561 | if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) | 1563 | if (!(registered_fb[i]->flags & FBINFO_MISC_FIRMWARE)) |
| 1562 | continue; | 1564 | continue; |
| 1563 | 1565 | ||
| 1564 | gen_aper = registered_fb[i]->apertures; | 1566 | gen_aper = registered_fb[i]->apertures; |
| 1567 | device = registered_fb[i]->device; | ||
| 1565 | if (fb_do_apertures_overlap(gen_aper, a) || | 1568 | if (fb_do_apertures_overlap(gen_aper, a) || |
| 1566 | (primary && gen_aper && gen_aper->count && | 1569 | (primary && gen_aper && gen_aper->count && |
| 1567 | gen_aper->ranges[0].base == VGA_FB_PHYS)) { | 1570 | gen_aper->ranges[0].base == VGA_FB_PHYS)) { |
| 1568 | 1571 | ||
| 1569 | printk(KERN_INFO "fb%d: switching to %s from %s\n", | 1572 | printk(KERN_INFO "fb%d: switching to %s from %s\n", |
| 1570 | i, name, registered_fb[i]->fix.id); | 1573 | i, name, registered_fb[i]->fix.id); |
| 1571 | do_unregister_framebuffer(registered_fb[i]); | 1574 | |
| 1575 | /* | ||
| 1576 | * If we kick-out a firmware driver, we also want to remove | ||
| 1577 | * the underlying platform device, such as simple-framebuffer, | ||
| 1578 | * VESA, EFI, etc. A native driver will then be able to | ||
| 1579 | * allocate the memory range. | ||
| 1580 | * | ||
| 1581 | * If it's not a platform device, at least print a warning. A | ||
| 1582 | * fix would add code to remove the device from the system. | ||
| 1583 | */ | ||
| 1584 | if (dev_is_platform(device)) { | ||
| 1585 | registered_fb[i]->forced_out = true; | ||
| 1586 | platform_device_unregister(to_platform_device(device)); | ||
| 1587 | } else { | ||
| 1588 | pr_warn("fb%d: cannot remove device\n", i); | ||
| 1589 | do_unregister_framebuffer(registered_fb[i]); | ||
| 1590 | } | ||
| 1572 | } | 1591 | } |
| 1573 | } | 1592 | } |
| 1574 | } | 1593 | } |
| @@ -1898,9 +1917,13 @@ EXPORT_SYMBOL(register_framebuffer); · 323 unmodified lines | |||
| 1898 | void | 1917 | void |
| 1899 | unregister_framebuffer(struct fb_info *fb_info) | 1918 | unregister_framebuffer(struct fb_info *fb_info) |
| 1900 | { | 1919 | { |
| 1901 | mutex_lock(®istration_lock); | 1920 | bool forced_out = fb_info->forced_out; |
| 1921 | |||
| 1922 | if (!forced_out) | ||
| 1923 | mutex_lock(®istration_lock); | ||
| 1902 | do_unregister_framebuffer(fb_info); | 1924 | do_unregister_framebuffer(fb_info); |
| 1903 | mutex_unlock(®istration_lock); | 1925 | if (!forced_out) |
| 1926 | mutex_unlock(®istration_lock); | ||
| 1904 | } | 1927 | } |
| 1905 | EXPORT_SYMBOL(unregister_framebuffer); | 1928 | EXPORT_SYMBOL(unregister_framebuffer); |
| 1906 | 1929 | ||
| @@ -489,7 +489,7 @@ static int s3c_fb_set_par(struct fb_info *info) · 488 unmodified lines | |||
| 489 | struct s3c_fb_win *win = info->par; | 489 | struct s3c_fb_win *win = info->par; |
| 490 | struct s3c_fb *sfb = win->parent; | 490 | struct s3c_fb *sfb = win->parent; |
| 491 | void __iomem *regs = sfb->regs; | 491 | void __iomem *regs = sfb->regs; |
| 492 | void __iomem *buf = regs; | 492 | void __iomem *buf; |
| 493 | int win_no = win->index; | 493 | int win_no = win->index; |
| 494 | u32 alpha = 0; | 494 | u32 alpha = 0; |
| 495 | u32 data; | 495 | u32 data; |
| @@ -66,16 +66,36 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue, · 65 unmodified lines | |||
| 66 | return 0; | 66 | return 0; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | struct simplefb_par; | 69 | struct simplefb_par { |
| 70 | u32 palette[PSEUDO_PALETTE_SIZE]; | ||
| 71 | struct resource *mem; | ||
| 72 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK | ||
| 73 | bool clks_enabled; | ||
| 74 | unsigned int clk_count; | ||
| 75 | struct clk **clks; | ||
| 76 | #endif | ||
| 77 | #if defined CONFIG_OF && defined CONFIG_REGULATOR | ||
| 78 | bool regulators_enabled; | ||
| 79 | u32 regulator_count; | ||
| 80 | struct regulator **regulators; | ||
| 81 | #endif | ||
| 82 | }; | ||
| 83 | |||
| 70 | static void simplefb_clocks_destroy(struct simplefb_par *par); | 84 | static void simplefb_clocks_destroy(struct simplefb_par *par); |
| 71 | static void simplefb_regulators_destroy(struct simplefb_par *par); | 85 | static void simplefb_regulators_destroy(struct simplefb_par *par); |
| 72 | 86 | ||
| 73 | static void simplefb_destroy(struct fb_info *info) | 87 | static void simplefb_destroy(struct fb_info *info) |
| 74 | { | 88 | { |
| 89 | struct simplefb_par *par = info->par; | ||
| 90 | struct resource *mem = par->mem; | ||
| 91 | |||
| 75 | simplefb_regulators_destroy(info->par); | 92 | simplefb_regulators_destroy(info->par); |
| 76 | simplefb_clocks_destroy(info->par); | 93 | simplefb_clocks_destroy(info->par); |
| 77 | if (info->screen_base) | 94 | if (info->screen_base) |
| 78 | iounmap(info->screen_base); | 95 | iounmap(info->screen_base); |
| 96 | |||
| 97 | if (mem) | ||
| 98 | release_mem_region(mem->start, resource_size(mem)); | ||
| 79 | } | 99 | } |
| 80 | 100 | ||
| 81 | static const struct fb_ops simplefb_ops = { | 101 | static const struct fb_ops simplefb_ops = { |
| @@ -169,20 +189,6 @@ static int simplefb_parse_pd(struct platform_device *pdev, · 87 unmodified lines | |||
| 169 | return 0; | 189 | return 0; |
| 170 | } | 190 | } |
| 171 | 191 | ||
| 172 | struct simplefb_par { | ||
| 173 | u32 palette[PSEUDO_PALETTE_SIZE]; | ||
| 174 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK | ||
| 175 | bool clks_enabled; | ||
| 176 | unsigned int clk_count; | ||
| 177 | struct clk **clks; | ||
| 178 | #endif | ||
| 179 | #if defined CONFIG_OF && defined CONFIG_REGULATOR | ||
| 180 | bool regulators_enabled; | ||
| 181 | u32 regulator_count; | ||
| 182 | struct regulator **regulators; | ||
| 183 | #endif | ||
| 184 | }; | ||
| 185 | |||
| 186 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK | 192 | #if defined CONFIG_OF && defined CONFIG_COMMON_CLK |
| 187 | /* | 193 | /* |
| 188 | * Clock handling code. | 194 | * Clock handling code. |
| @@ -405,7 +411,7 @@ static int simplefb_probe(struct platform_device *pdev) · 216 unmodified lines | |||
| 405 | struct simplefb_params params; | 411 | struct simplefb_params params; |
| 406 | struct fb_info *info; | 412 | struct fb_info *info; |
| 407 | struct simplefb_par *par; | 413 | struct simplefb_par *par; |
| 408 | struct resource *mem; | 414 | struct resource *res, *mem; |
| 409 | 415 | ||
| 410 | /* | 416 | /* |
| 411 | * Generic drivers must not be registered if a framebuffer exists. | 417 | * Generic drivers must not be registered if a framebuffer exists. |
| @@ -430,15 +436,28 @@ static int simplefb_probe(struct platform_device *pdev) · 18 unmodified lines | |||
| 430 | if (ret) | 436 | if (ret) |
| 431 | return ret; | 437 | return ret; |
| 432 | 438 | ||
| 433 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 439 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 434 | if (!mem) { | 440 | if (!res) { |
| 435 | dev_err(&pdev->dev, "No memory resource\n"); | 441 | dev_err(&pdev->dev, "No memory resource\n"); |
| 436 | return -EINVAL; | 442 | return -EINVAL; |
| 437 | } | 443 | } |
| 438 | 444 | ||
| 445 | mem = request_mem_region(res->start, resource_size(res), "simplefb"); | ||
| 446 | if (!mem) { | ||
| 447 | /* | ||
| 448 | * We cannot make this fatal. Sometimes this comes from magic | ||
| 449 | * spaces our resource handlers simply don't know about. Use | ||
| 450 | * the I/O-memory resource as-is and try to map that instead. | ||
| 451 | */ | ||
| 452 | dev_warn(&pdev->dev, "simplefb: cannot reserve video memory at %pR\n", res); | ||
| 453 | mem = res; | ||
| 454 | } | ||
| 455 | |||
| 439 | info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev); | 456 | info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev); |
| 440 | if (!info) | 457 | if (!info) { |
| 441 | return -ENOMEM; | 458 | ret = -ENOMEM; |
| 459 | goto error_release_mem_region; | ||
| 460 | } | ||
| 442 | platform_set_drvdata(pdev, info); | 461 | platform_set_drvdata(pdev, info); |
| 443 | 462 | ||
| 444 | par = info->par; | 463 | par = info->par; |
| @@ -495,6 +514,9 @@ static int simplefb_probe(struct platform_device *pdev) · 50 unmodified lines | |||
| 495 | info->var.xres, info->var.yres, | 514 | info->var.xres, info->var.yres, |
| 496 | info->var.bits_per_pixel, info->fix.line_length); | 515 | info->var.bits_per_pixel, info->fix.line_length); |
| 497 | 516 | ||
| 517 | if (mem != res) | ||
| 518 | par->mem = mem; /* release in clean-up handler */ | ||
| 519 | |||
| 498 | ret = register_framebuffer(info); | 520 | ret = register_framebuffer(info); |
| 499 | if (ret < 0) { | 521 | if (ret < 0) { |
| 500 | dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); | 522 | dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret); |
| @@ -513,6 +535,9 @@ error_unmap: · 12 unmodified lines | |||
| 513 | iounmap(info->screen_base); | 535 | iounmap(info->screen_base); |
| 514 | error_fb_release: | 536 | error_fb_release: |
| 515 | framebuffer_release(info); | 537 | framebuffer_release(info); |
| 538 | error_release_mem_region: | ||
| 539 | if (mem != res) | ||
| 540 | release_mem_region(mem->start, resource_size(mem)); | ||
| 516 | return ret; | 541 | return ret; |
| 517 | } | 542 | } |
| 518 | 543 | ||
| @@ -1351,7 +1351,12 @@ static int vga16fb_probe(struct platform_device *dev) · 1350 unmodified lines | |||
| 1351 | printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); | 1351 | printk(KERN_INFO "vga16fb: mapped to 0x%p\n", info->screen_base); |
| 1352 | par = info->par; | 1352 | par = info->par; |
| 1353 | 1353 | ||
| 1354 | #if defined(CONFIG_X86) | ||
| 1355 | par->isVGA = screen_info.orig_video_isVGA == VIDEO_TYPE_VGAC; | ||
| 1356 | #else | ||
| 1357 | /* non-x86 architectures treat orig_video_isVGA as a boolean flag */ | ||
| 1354 | par->isVGA = screen_info.orig_video_isVGA; | 1358 | par->isVGA = screen_info.orig_video_isVGA; |
| 1359 | #endif | ||
| 1355 | par->palette_blanked = 0; | 1360 | par->palette_blanked = 0; |
| 1356 | par->vesa_blanked = 0; | 1361 | par->vesa_blanked = 0; |
| 1357 | 1362 | ||
| @@ -51,7 +51,9 @@ struct dw_mipi_dsi_plat_data { · 50 unmodified lines | |||
| 51 | unsigned int max_data_lanes; | 51 | unsigned int max_data_lanes; |
| 52 | 52 | ||
| 53 | enum drm_mode_status (*mode_valid)(void *priv_data, | 53 | enum drm_mode_status (*mode_valid)(void *priv_data, |
| 54 | const struct drm_display_mode *mode); | 54 | const struct drm_display_mode *mode, |
| 55 | unsigned long mode_flags, | ||
| 56 | u32 lanes, u32 format); | ||
| 55 | 57 | ||
| 56 | const struct dw_mipi_dsi_phy_ops *phy_ops; | 58 | const struct dw_mipi_dsi_phy_ops *phy_ops; |
| 57 | const struct dw_mipi_dsi_host_ops *host_ops; | 59 | const struct dw_mipi_dsi_host_ops *host_ops; |
File renamed without changes.
File renamed without changes.
| @@ -1038,11 +1038,8 @@ struct drm_panel; · 1037 unmodified lines | |||
| 1038 | #define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600 /* 1.2 MST */ | 1038 | #define DP_SIDEBAND_MSG_UP_REQ_BASE 0x1600 /* 1.2 MST */ |
| 1039 | 1039 | ||
| 1040 | /* DPRX Event Status Indicator */ | 1040 | /* DPRX Event Status Indicator */ |
| 1041 | #define DP_SINK_COUNT_ESI 0x2002 /* 1.2 */ | 1041 | #define DP_SINK_COUNT_ESI 0x2002 /* same as 0x200 */ |
| 1042 | /* 0-5 sink count */ | 1042 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* same as 0x201 */ |
| 1043 | # define DP_SINK_COUNT_CP_READY (1 << 6) | ||
| 1044 | |||
| 1045 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI0 0x2003 /* 1.2 */ | ||
| 1046 | 1043 | ||
| 1047 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ | 1044 | #define DP_DEVICE_SERVICE_IRQ_VECTOR_ESI1 0x2004 /* 1.2 */ |
| 1048 | # define DP_RX_GTC_MSTR_REQ_STATUS_CHANGE (1 << 0) | 1045 | # define DP_RX_GTC_MSTR_REQ_STATUS_CHANGE (1 << 0) |
| @@ -23,7 +23,7 @@ · 22 unmodified lines | |||
| 23 | #define _DRM_DP_MST_HELPER_H_ | 23 | #define _DRM_DP_MST_HELPER_H_ |
| 24 | 24 | ||
| 25 | #include <linux/types.h> | 25 | #include <linux/types.h> |
| 26 | #include <drm/drm_dp_helper.h> | 26 | #include <drm/dp/drm_dp_helper.h> |
| 27 | #include <drm/drm_atomic.h> | 27 | #include <drm/drm_atomic.h> |
| 28 | 28 | ||
| 29 | #if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) | 29 | #if IS_ENABLED(CONFIG_DRM_DEBUG_DP_MST_TOPOLOGY_REFS) |
| @@ -0,0 +1,150 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2021 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef __DRM_BUDDY_H__ | ||
| 7 | #define __DRM_BUDDY_H__ | ||
| 8 | |||
| 9 | #include <linux/bitops.h> | ||
| 10 | #include <linux/list.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/sched.h> | ||
| 13 | |||
| 14 | #include <drm/drm_print.h> | ||
| 15 | |||
| 16 | #define range_overflows(start, size, max) ({ \ | ||
| 17 | typeof(start) start__ = (start); \ | ||
| 18 | typeof(size) size__ = (size); \ | ||
| 19 | typeof(max) max__ = (max); \ | ||
| 20 | (void)(&start__ == &size__); \ | ||
| 21 | (void)(&start__ == &max__); \ | ||
| 22 | start__ >= max__ || size__ > max__ - start__; \ | ||
| 23 | }) | ||
| 24 | |||
| 25 | struct drm_buddy_block { | ||
| 26 | #define DRM_BUDDY_HEADER_OFFSET GENMASK_ULL(63, 12) | ||
| 27 | #define DRM_BUDDY_HEADER_STATE GENMASK_ULL(11, 10) | ||
| 28 | #define DRM_BUDDY_ALLOCATED (1 << 10) | ||
| 29 | #define DRM_BUDDY_FREE (2 << 10) | ||
| 30 | #define DRM_BUDDY_SPLIT (3 << 10) | ||
| 31 | /* Free to be used, if needed in the future */ | ||
| 32 | #define DRM_BUDDY_HEADER_UNUSED GENMASK_ULL(9, 6) | ||
| 33 | #define DRM_BUDDY_HEADER_ORDER GENMASK_ULL(5, 0) | ||
| 34 | u64 header; | ||
| 35 | |||
| 36 | struct drm_buddy_block *left; | ||
| 37 | struct drm_buddy_block *right; | ||
| 38 | struct drm_buddy_block *parent; | ||
| 39 | |||
| 40 | void *private; /* owned by creator */ | ||
| 41 | |||
| 42 | /* | ||
| 43 | * While the block is allocated by the user through drm_buddy_alloc*, | ||
| 44 | * the user has ownership of the link, for example to maintain within | ||
| 45 | * a list, if so desired. As soon as the block is freed with | ||
| 46 | * drm_buddy_free* ownership is given back to the mm. | ||
| 47 | */ | ||
| 48 | struct list_head link; | ||
| 49 | struct list_head tmp_link; | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* Order-zero must be at least PAGE_SIZE */ | ||
| 53 | #define DRM_BUDDY_MAX_ORDER (63 - PAGE_SHIFT) | ||
| 54 | |||
| 55 | /* | ||
| 56 | * Binary Buddy System. | ||
| 57 | * | ||
| 58 | * Locking should be handled by the user, a simple mutex around | ||
| 59 | * drm_buddy_alloc* and drm_buddy_free* should suffice. | ||
| 60 | */ | ||
| 61 | struct drm_buddy { | ||
| 62 | /* Maintain a free list for each order. */ | ||
| 63 | struct list_head *free_list; | ||
| 64 | |||
| 65 | /* | ||
| 66 | * Maintain explicit binary tree(s) to track the allocation of the | ||
| 67 | * address space. This gives us a simple way of finding a buddy block | ||
| 68 | * and performing the potentially recursive merge step when freeing a | ||
| 69 | * block. Nodes are either allocated or free, in which case they will | ||
| 70 | * also exist on the respective free list. | ||
| 71 | */ | ||
| 72 | struct drm_buddy_block **roots; | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Anything from here is public, and remains static for the lifetime of | ||
| 76 | * the mm. Everything above is considered do-not-touch. | ||
| 77 | */ | ||
| 78 | unsigned int n_roots; | ||
| 79 | unsigned int max_order; | ||
| 80 | |||
| 81 | /* Must be at least PAGE_SIZE */ | ||
| 82 | u64 chunk_size; | ||
| 83 | u64 size; | ||
| 84 | u64 avail; | ||
| 85 | }; | ||
| 86 | |||
| 87 | static inline u64 | ||
| 88 | drm_buddy_block_offset(struct drm_buddy_block *block) | ||
| 89 | { | ||
| 90 | return block->header & DRM_BUDDY_HEADER_OFFSET; | ||
| 91 | } | ||
| 92 | |||
| 93 | static inline unsigned int | ||
| 94 | drm_buddy_block_order(struct drm_buddy_block *block) | ||
| 95 | { | ||
| 96 | return block->header & DRM_BUDDY_HEADER_ORDER; | ||
| 97 | } | ||
| 98 | |||
| 99 | static inline unsigned int | ||
| 100 | drm_buddy_block_state(struct drm_buddy_block *block) | ||
| 101 | { | ||
| 102 | return block->header & DRM_BUDDY_HEADER_STATE; | ||
| 103 | } | ||
| 104 | |||
| 105 | static inline bool | ||
| 106 | drm_buddy_block_is_allocated(struct drm_buddy_block *block) | ||
| 107 | { | ||
| 108 | return drm_buddy_block_state(block) == DRM_BUDDY_ALLOCATED; | ||
| 109 | } | ||
| 110 | |||
| 111 | static inline bool | ||
| 112 | drm_buddy_block_is_free(struct drm_buddy_block *block) | ||
| 113 | { | ||
| 114 | return drm_buddy_block_state(block) == DRM_BUDDY_FREE; | ||
| 115 | } | ||
| 116 | |||
| 117 | static inline bool | ||
| 118 | drm_buddy_block_is_split(struct drm_buddy_block *block) | ||
| 119 | { | ||
| 120 | return drm_buddy_block_state(block) == DRM_BUDDY_SPLIT; | ||
| 121 | } | ||
| 122 | |||
| 123 | static inline u64 | ||
| 124 | drm_buddy_block_size(struct drm_buddy *mm, | ||
| 125 | struct drm_buddy_block *block) | ||
| 126 | { | ||
| 127 | return mm->chunk_size << drm_buddy_block_order(block); | ||
| 128 | } | ||
| 129 | |||
| 130 | int drm_buddy_init(struct drm_buddy *mm, u64 size, u64 chunk_size); | ||
| 131 | |||
| 132 | void drm_buddy_fini(struct drm_buddy *mm); | ||
| 133 | |||
| 134 | struct drm_buddy_block * | ||
| 135 | drm_buddy_alloc_blocks(struct drm_buddy *mm, unsigned int order); | ||
| 136 | |||
| 137 | int drm_buddy_alloc_range(struct drm_buddy *mm, | ||
| 138 | struct list_head *blocks, | ||
| 139 | u64 start, u64 size); | ||
| 140 | |||
| 141 | void drm_buddy_free_block(struct drm_buddy *mm, struct drm_buddy_block *block); | ||
| 142 | |||
| 143 | void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects); | ||
| 144 | |||
| 145 | void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p); | ||
| 146 | void drm_buddy_block_print(struct drm_buddy *mm, | ||
| 147 | struct drm_buddy_block *block, | ||
| 148 | struct drm_printer *p); | ||
| 149 | |||
| 150 | #endif | ||
| @@ -522,9 +522,9 @@ struct drm_display_info { · 521 unmodified lines | |||
| 522 | enum subpixel_order subpixel_order; | 522 | enum subpixel_order subpixel_order; |
| 523 | 523 | ||
| 524 | #define DRM_COLOR_FORMAT_RGB444 (1<<0) | 524 | #define DRM_COLOR_FORMAT_RGB444 (1<<0) |
| 525 | #define DRM_COLOR_FORMAT_YCRCB444 (1<<1) | 525 | #define DRM_COLOR_FORMAT_YCBCR444 (1<<1) |
| 526 | #define DRM_COLOR_FORMAT_YCRCB422 (1<<2) | 526 | #define DRM_COLOR_FORMAT_YCBCR422 (1<<2) |
| 527 | #define DRM_COLOR_FORMAT_YCRCB420 (1<<3) | 527 | #define DRM_COLOR_FORMAT_YCBCR420 (1<<3) |
| 528 | 528 | ||
| 529 | /** | 529 | /** |
| 530 | * @panel_orientation: Read only connector property for built-in panels, | 530 | * @panel_orientation: Read only connector property for built-in panels, |
| @@ -592,10 +592,16 @@ struct drm_display_info { · 61 unmodified lines | |||
| 592 | bool rgb_quant_range_selectable; | 592 | bool rgb_quant_range_selectable; |
| 593 | 593 | ||
| 594 | /** | 594 | /** |
| 595 | * @edid_hdmi_dc_modes: Mask of supported hdmi deep color modes. Even | 595 | * @edid_hdmi_dc_rgb444_modes: Mask of supported hdmi deep color modes |
| 596 | * more stuff redundant with @bus_formats. | 596 | * in RGB 4:4:4. Even more stuff redundant with @bus_formats. |
| 597 | */ | 597 | */ |
| 598 | u8 edid_hdmi_dc_modes; | 598 | u8 edid_hdmi_rgb444_dc_modes; |
| 599 | |||
| 600 | /** | ||
| 601 | * @edid_hdmi_dc_ycbcr444_modes: Mask of supported hdmi deep color | ||
| 602 | * modes in YCbCr 4:4:4. Even more stuff redundant with @bus_formats. | ||
| 603 | */ | ||
| 604 | u8 edid_hdmi_ycbcr444_dc_modes; | ||
| 599 | 605 | ||
| 600 | /** | 606 | /** |
| 601 | * @cea_rev: CEA revision of the HDMI sink. | 607 | * @cea_rev: CEA revision of the HDMI sink. |
| @@ -285,6 +285,10 @@ struct drm_crtc_state { · 284 unmodified lines | |||
| 285 | * Lookup table for converting pixel data after the color conversion | 285 | * Lookup table for converting pixel data after the color conversion |
| 286 | * matrix @ctm. See drm_crtc_enable_color_mgmt(). The blob (if not | 286 | * matrix @ctm. See drm_crtc_enable_color_mgmt(). The blob (if not |
| 287 | * NULL) is an array of &struct drm_color_lut. | 287 | * NULL) is an array of &struct drm_color_lut. |
| 288 | * | ||
| 289 | * Note that for mostly historical reasons stemming from Xorg heritage, | ||
| 290 | * this is also used to store the color map (also sometimes color lut, | ||
| 291 | * CLUT or color palette) for indexed formats like DRM_FORMAT_C8. | ||
| 288 | */ | 292 | */ |
| 289 | struct drm_property_blob *gamma_lut; | 293 | struct drm_property_blob *gamma_lut; |
| 290 | 294 | ||
| @@ -1075,12 +1079,18 @@ struct drm_crtc { · 784 unmodified lines | |||
| 1075 | /** | 1079 | /** |
| 1076 | * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up | 1080 | * @gamma_size: Size of legacy gamma ramp reported to userspace. Set up |
| 1077 | * by calling drm_mode_crtc_set_gamma_size(). | 1081 | * by calling drm_mode_crtc_set_gamma_size(). |
| 1082 | * | ||
| 1083 | * Note that atomic drivers need to instead use | ||
| 1084 | * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt(). | ||
| 1078 | */ | 1085 | */ |
| 1079 | uint32_t gamma_size; | 1086 | uint32_t gamma_size; |
| 1080 | 1087 | ||
| 1081 | /** | 1088 | /** |
| 1082 | * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and | 1089 | * @gamma_store: Gamma ramp values used by the legacy SETGAMMA and |
| 1083 | * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size(). | 1090 | * GETGAMMA IOCTls. Set up by calling drm_mode_crtc_set_gamma_size(). |
| 1091 | * | ||
| 1092 | * Note that atomic drivers need to instead use | ||
| 1093 | * &drm_crtc_state.gamma_lut. See drm_crtc_enable_color_mgmt(). | ||
| 1084 | */ | 1094 | */ |
| 1085 | uint16_t *gamma_store; | 1095 | uint16_t *gamma_store; |
| 1086 | 1096 | ||
| @@ -8,7 +8,7 @@ · 7 unmodified lines | |||
| 8 | #ifndef DRM_DSC_H_ | 8 | #ifndef DRM_DSC_H_ |
| 9 | #define DRM_DSC_H_ | 9 | #define DRM_DSC_H_ |
| 10 | 10 | ||
| 11 | #include <drm/drm_dp_helper.h> | 11 | #include <drm/dp/drm_dp_helper.h> |
| 12 | 12 | ||
| 13 | /* VESA Display Stream Compression DSC 1.2 constants */ | 13 | /* VESA Display Stream Compression DSC 1.2 constants */ |
| 14 | #define DSC_NUM_BUF_RANGES 15 | 14 | #define DSC_NUM_BUF_RANGES 15 |
| @@ -401,8 +401,8 @@ drm_hdmi_vendor_infoframe_from_display_mode(struct hdmi_vendor_infoframe *frame, · 400 unmodified lines | |||
| 401 | const struct drm_display_mode *mode); | 401 | const struct drm_display_mode *mode); |
| 402 | 402 | ||
| 403 | void | 403 | void |
| 404 | drm_hdmi_avi_infoframe_colorspace(struct hdmi_avi_infoframe *frame, | 404 | drm_hdmi_avi_infoframe_colorimetry(struct hdmi_avi_infoframe *frame, |
| 405 | const struct drm_connector_state *conn_state); | 405 | const struct drm_connector_state *conn_state); |
| 406 | 406 | ||
| 407 | void | 407 | void |
| 408 | drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, | 408 | drm_hdmi_avi_infoframe_bars(struct hdmi_avi_infoframe *frame, |
| @@ -194,7 +194,7 @@ int mipi_dbi_buf_copy(void *dst, struct drm_framebuffer *fb, · 193 unmodified lines | |||
| 194 | #ifdef CONFIG_DEBUG_FS | 194 | #ifdef CONFIG_DEBUG_FS |
| 195 | void mipi_dbi_debugfs_init(struct drm_minor *minor); | 195 | void mipi_dbi_debugfs_init(struct drm_minor *minor); |
| 196 | #else | 196 | #else |
| 197 | #define mipi_dbi_debugfs_init NULL | 197 | static inline void mipi_dbi_debugfs_init(struct drm_minor *minor) {} |
| 198 | #endif | 198 | #endif |
| 199 | 199 | ||
| 200 | #endif /* __LINUX_MIPI_DBI_H */ | 200 | #endif /* __LINUX_MIPI_DBI_H */ |
| @@ -34,6 +34,7 @@ struct drm_modeset_lock; · 33 unmodified lines | |||
| 34 | * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) | 34 | * struct drm_modeset_acquire_ctx - locking context (see ww_acquire_ctx) |
| 35 | * @ww_ctx: base acquire ctx | 35 | * @ww_ctx: base acquire ctx |
| 36 | * @contended: used internally for -EDEADLK handling | 36 | * @contended: used internally for -EDEADLK handling |
| 37 | * @stack_depot: used internally for contention debugging | ||
| 37 | * @locked: list of held locks | 38 | * @locked: list of held locks |
| 38 | * @trylock_only: trylock mode used in atomic contexts/panic notifiers | 39 | * @trylock_only: trylock mode used in atomic contexts/panic notifiers |
| 39 | * @interruptible: whether interruptible locking should be used. | 40 | * @interruptible: whether interruptible locking should be used. |
| @@ -0,0 +1,125 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | |||
| 3 | #ifndef DRM_MODULE_H | ||
| 4 | #define DRM_MODULE_H | ||
| 5 | |||
| 6 | #include <linux/pci.h> | ||
| 7 | #include <linux/platform_device.h> | ||
| 8 | |||
| 9 | #include <drm/drm_drv.h> | ||
| 10 | |||
| 11 | /** | ||
| 12 | * DOC: overview | ||
| 13 | * | ||
| 14 | * This library provides helpers registering DRM drivers during module | ||
| 15 | * initialization and shutdown. The provided helpers act like bus-specific | ||
| 16 | * module helpers, such as module_pci_driver(), but respect additional | ||
| 17 | * parameters that control DRM driver registration. | ||
| 18 | * | ||
| 19 | * Below is an example of initializing a DRM driver for a device on the | ||
| 20 | * PCI bus. | ||
| 21 | * | ||
| 22 | * .. code-block:: c | ||
| 23 | * | ||
| 24 | * struct pci_driver my_pci_drv = { | ||
| 25 | * }; | ||
| 26 | * | ||
| 27 | * drm_module_pci_driver(my_pci_drv); | ||
| 28 | * | ||
| 29 | * The generated code will test if DRM drivers are enabled and register | ||
| 30 | * the PCI driver my_pci_drv. For more complex module initialization, you | ||
| 31 | * can still use module_init() and module_exit() in your driver. | ||
| 32 | */ | ||
| 33 | |||
| 34 | /* | ||
| 35 | * PCI drivers | ||
| 36 | */ | ||
| 37 | |||
| 38 | static inline int __init drm_pci_register_driver(struct pci_driver *pci_drv) | ||
| 39 | { | ||
| 40 | if (drm_firmware_drivers_only()) | ||
| 41 | return -ENODEV; | ||
| 42 | |||
| 43 | return pci_register_driver(pci_drv); | ||
| 44 | } | ||
| 45 | |||
| 46 | /** | ||
| 47 | * drm_module_pci_driver - Register a DRM driver for PCI-based devices | ||
| 48 | * @__pci_drv: the PCI driver structure | ||
| 49 | * | ||
| 50 | * Registers a DRM driver for devices on the PCI bus. The helper | ||
| 51 | * macro behaves like module_pci_driver() but tests the state of | ||
| 52 | * drm_firmware_drivers_only(). For more complex module initialization, | ||
| 53 | * use module_init() and module_exit() directly. | ||
| 54 | * | ||
| 55 | * Each module may only use this macro once. Calling it replaces | ||
| 56 | * module_init() and module_exit(). | ||
| 57 | */ | ||
| 58 | #define drm_module_pci_driver(__pci_drv) \ | ||
| 59 | module_driver(__pci_drv, drm_pci_register_driver, pci_unregister_driver) | ||
| 60 | |||
| 61 | static inline int __init | ||
| 62 | drm_pci_register_driver_if_modeset(struct pci_driver *pci_drv, int modeset) | ||
| 63 | { | ||
| 64 | if (drm_firmware_drivers_only() && modeset == -1) | ||
| 65 | return -ENODEV; | ||
| 66 | if (modeset == 0) | ||
| 67 | return -ENODEV; | ||
| 68 | |||
| 69 | return pci_register_driver(pci_drv); | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline void __exit | ||
| 73 | drm_pci_unregister_driver_if_modeset(struct pci_driver *pci_drv, int modeset) | ||
| 74 | { | ||
| 75 | pci_unregister_driver(pci_drv); | ||
| 76 | } | ||
| 77 | |||
| 78 | /** | ||
| 79 | * drm_module_pci_driver_if_modeset - Register a DRM driver for PCI-based devices | ||
| 80 | * @__pci_drv: the PCI driver structure | ||
| 81 | * @__modeset: an additional parameter that disables the driver | ||
| 82 | * | ||
| 83 | * This macro is deprecated and only provided for existing drivers. For | ||
| 84 | * new drivers, use drm_module_pci_driver(). | ||
| 85 | * | ||
| 86 | * Registers a DRM driver for devices on the PCI bus. The helper macro | ||
| 87 | * behaves like drm_module_pci_driver() with an additional driver-specific | ||
| 88 | * flag. If __modeset is 0, the driver has been disabled, if __modeset is | ||
| 89 | * -1 the driver state depends on the global DRM state. For all other | ||
| 90 | * values, the PCI driver has been enabled. The default should be -1. | ||
| 91 | */ | ||
| 92 | #define drm_module_pci_driver_if_modeset(__pci_drv, __modeset) \ | ||
| 93 | module_driver(__pci_drv, drm_pci_register_driver_if_modeset, \ | ||
| 94 | drm_pci_unregister_driver_if_modeset, __modeset) | ||
| 95 | |||
| 96 | /* | ||
| 97 | * Platform drivers | ||
| 98 | */ | ||
| 99 | |||
| 100 | static inline int __init | ||
| 101 | drm_platform_driver_register(struct platform_driver *platform_drv) | ||
| 102 | { | ||
| 103 | if (drm_firmware_drivers_only()) | ||
| 104 | return -ENODEV; | ||
| 105 | |||
| 106 | return platform_driver_register(platform_drv); | ||
| 107 | } | ||
| 108 | |||
| 109 | /** | ||
| 110 | * drm_module_platform_driver - Register a DRM driver for platform devices | ||
| 111 | * @__platform_drv: the platform driver structure | ||
| 112 | * | ||
| 113 | * Registers a DRM driver for devices on the platform bus. The helper | ||
| 114 | * macro behaves like module_platform_driver() but tests the state of | ||
| 115 | * drm_firmware_drivers_only(). For more complex module initialization, | ||
| 116 | * use module_init() and module_exit() directly. | ||
| 117 | * | ||
| 118 | * Each module may only use this macro once. Calling it replaces | ||
| 119 | * module_init() and module_exit(). | ||
| 120 | */ | ||
| 121 | #define drm_module_platform_driver(__platform_drv) \ | ||
| 122 | module_driver(__platform_drv, drm_platform_driver_register, \ | ||
| 123 | platform_driver_unregister) | ||
| 124 | |||
| 125 | #endif | ||
| @@ -516,7 +516,7 @@ struct drm_plane_funcs { · 515 unmodified lines | |||
| 516 | * This optional hook is used for the DRM to determine if the given | 516 | * This optional hook is used for the DRM to determine if the given |
| 517 | * format/modifier combination is valid for the plane. This allows the | 517 | * format/modifier combination is valid for the plane. This allows the |
| 518 | * DRM to generate the correct format bitmask (which formats apply to | 518 | * DRM to generate the correct format bitmask (which formats apply to |
| 519 | * which modifier), and to valdiate modifiers at atomic_check time. | 519 | * which modifier), and to validate modifiers at atomic_check time. |
| 520 | * | 520 | * |
| 521 | * If not present, then any modifier in the plane's modifier | 521 | * If not present, then any modifier in the plane's modifier |
| 522 | * list is allowed with any of the plane's formats. | 522 | * list is allowed with any of the plane's formats. |
| @@ -73,10 +73,21 @@ struct drm_privacy_screen { · 72 unmodified lines | |||
| 73 | * for more info. | 73 | * for more info. |
| 74 | */ | 74 | */ |
| 75 | enum drm_privacy_screen_status hw_state; | 75 | enum drm_privacy_screen_status hw_state; |
| 76 | /** | ||
| 77 | * @drvdata: Private data owned by the privacy screen provider | ||
| 78 | */ | ||
| 79 | void *drvdata; | ||
| 76 | }; | 80 | }; |
| 77 | 81 | ||
| 82 | static inline | ||
| 83 | void *drm_privacy_screen_get_drvdata(struct drm_privacy_screen *priv) | ||
| 84 | { | ||
| 85 | return priv->drvdata; | ||
| 86 | } | ||
| 87 | |||
| 78 | struct drm_privacy_screen *drm_privacy_screen_register( | 88 | struct drm_privacy_screen *drm_privacy_screen_register( |
| 79 | struct device *parent, const struct drm_privacy_screen_ops *ops); | 89 | struct device *parent, const struct drm_privacy_screen_ops *ops, |
| 90 | void *data); | ||
| 80 | void drm_privacy_screen_unregister(struct drm_privacy_screen *priv); | 91 | void drm_privacy_screen_unregister(struct drm_privacy_screen *priv); |
| 81 | 92 | ||
| 82 | void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv); | 93 | void drm_privacy_screen_call_notifier_chain(struct drm_privacy_screen *priv); |
| @@ -105,11 +105,11 @@ struct ttm_resource_manager_func { · 104 unmodified lines | |||
| 105 | * @use_type: The memory type is enabled. | 105 | * @use_type: The memory type is enabled. |
| 106 | * @use_tt: If a TT object should be used for the backing store. | 106 | * @use_tt: If a TT object should be used for the backing store. |
| 107 | * @size: Size of the managed region. | 107 | * @size: Size of the managed region. |
| 108 | * @bdev: ttm device this manager belongs to | ||
| 108 | * @func: structure pointer implementing the range manager. See above | 109 | * @func: structure pointer implementing the range manager. See above |
| 109 | * @move_lock: lock for move fence | 110 | * @move_lock: lock for move fence |
| 110 | * static information. bdev::driver::io_mem_free is never used. | ||
| 111 | * @lru: The lru list for this memory type. | ||
| 112 | * @move: The fence of the last pipelined move operation. | 111 | * @move: The fence of the last pipelined move operation. |
| 112 | * @lru: The lru list for this memory type. | ||
| 113 | * | 113 | * |
| 114 | * This structure is used to identify and manage memory types for a device. | 114 | * This structure is used to identify and manage memory types for a device. |
| 115 | */ | 115 | */ |
| @@ -119,20 +119,21 @@ struct ttm_resource_manager { · 3 unmodified lines | |||
| 119 | */ | 119 | */ |
| 120 | bool use_type; | 120 | bool use_type; |
| 121 | bool use_tt; | 121 | bool use_tt; |
| 122 | struct ttm_device *bdev; | ||
| 122 | uint64_t size; | 123 | uint64_t size; |
| 123 | const struct ttm_resource_manager_func *func; | 124 | const struct ttm_resource_manager_func *func; |
| 124 | spinlock_t move_lock; | 125 | spinlock_t move_lock; |
| 125 | 126 | ||
| 126 | /* | 127 | /* |
| 127 | * Protected by the global->lru_lock. | 128 | * Protected by @move_lock. |
| 128 | */ | 129 | */ |
| 129 | 130 | struct dma_fence *move; | |
| 130 | struct list_head lru[TTM_MAX_BO_PRIORITY]; | ||
| 131 | 131 | ||
| 132 | /* | 132 | /* |
| 133 | * Protected by @move_lock. | 133 | * Protected by the global->lru_lock. |
| 134 | */ | 134 | */ |
| 135 | struct dma_fence *move; | 135 | |
| 136 | struct list_head lru[TTM_MAX_BO_PRIORITY]; | ||
| 136 | }; | 137 | }; |
| 137 | 138 | ||
| 138 | /** | 139 | /** |
| @@ -160,6 +161,7 @@ struct ttm_bus_placement { · 21 unmodified lines | |||
| 160 | * @mem_type: Resource type of the allocation. | 161 | * @mem_type: Resource type of the allocation. |
| 161 | * @placement: Placement flags. | 162 | * @placement: Placement flags. |
| 162 | * @bus: Placement on io bus accessible to the CPU | 163 | * @bus: Placement on io bus accessible to the CPU |
| 164 | * @bo: weak reference to the BO, protected by ttm_device::lru_lock | ||
| 163 | * | 165 | * |
| 164 | * Structure indicating the placement and space resources used by a | 166 | * Structure indicating the placement and space resources used by a |
| 165 | * buffer object. | 167 | * buffer object. |
| @@ -170,6 +172,7 @@ struct ttm_resource { · 4 unmodified lines | |||
| 170 | uint32_t mem_type; | 172 | uint32_t mem_type; |
| 171 | uint32_t placement; | 173 | uint32_t placement; |
| 172 | struct ttm_bus_placement bus; | 174 | struct ttm_bus_placement bus; |
| 175 | struct ttm_buffer_object *bo; | ||
| 173 | }; | 176 | }; |
| 174 | 177 | ||
| 175 | /** | 178 | /** |
| @@ -261,14 +264,20 @@ ttm_resource_manager_cleanup(struct ttm_resource_manager *man) · 85 unmodified lines | |||
| 261 | void ttm_resource_init(struct ttm_buffer_object *bo, | 264 | void ttm_resource_init(struct ttm_buffer_object *bo, |
| 262 | const struct ttm_place *place, | 265 | const struct ttm_place *place, |
| 263 | struct ttm_resource *res); | 266 | struct ttm_resource *res); |
| 267 | void ttm_resource_fini(struct ttm_resource_manager *man, | ||
| 268 | struct ttm_resource *res); | ||
| 269 | |||
| 264 | int ttm_resource_alloc(struct ttm_buffer_object *bo, | 270 | int ttm_resource_alloc(struct ttm_buffer_object *bo, |
| 265 | const struct ttm_place *place, | 271 | const struct ttm_place *place, |
| 266 | struct ttm_resource **res); | 272 | struct ttm_resource **res); |
| 267 | void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res); | 273 | void ttm_resource_free(struct ttm_buffer_object *bo, struct ttm_resource **res); |
| 268 | bool ttm_resource_compat(struct ttm_resource *res, | 274 | bool ttm_resource_compat(struct ttm_resource *res, |
| 269 | struct ttm_placement *placement); | 275 | struct ttm_placement *placement); |
| 276 | void ttm_resource_set_bo(struct ttm_resource *res, | ||
| 277 | struct ttm_buffer_object *bo); | ||
| 270 | 278 | ||
| 271 | void ttm_resource_manager_init(struct ttm_resource_manager *man, | 279 | void ttm_resource_manager_init(struct ttm_resource_manager *man, |
| 280 | struct ttm_device *bdev, | ||
| 272 | unsigned long p_size); | 281 | unsigned long p_size); |
| 273 | 282 | ||
| 274 | int ttm_resource_manager_evict_all(struct ttm_device *bdev, | 283 | int ttm_resource_manager_evict_all(struct ttm_device *bdev, |
| @@ -52,13 +52,13 @@ · 51 unmodified lines | |||
| 52 | * | 52 | * |
| 53 | * struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(0xdeadbeaf); | 53 | * struct dma_buf_map map = DMA_BUF_MAP_INIT_VADDR(0xdeadbeaf); |
| 54 | * | 54 | * |
| 55 | * dma_buf_map_set_vaddr(&map. 0xdeadbeaf); | 55 | * dma_buf_map_set_vaddr(&map, 0xdeadbeaf); |
| 56 | * | 56 | * |
| 57 | * To set an address in I/O memory, use dma_buf_map_set_vaddr_iomem(). | 57 | * To set an address in I/O memory, use dma_buf_map_set_vaddr_iomem(). |
| 58 | * | 58 | * |
| 59 | * .. code-block:: c | 59 | * .. code-block:: c |
| 60 | * | 60 | * |
| 61 | * dma_buf_map_set_vaddr_iomem(&map. 0xdeadbeaf); | 61 | * dma_buf_map_set_vaddr_iomem(&map, 0xdeadbeaf); |
| 62 | * | 62 | * |
| 63 | * Instances of struct dma_buf_map do not have to be cleaned up, but | 63 | * Instances of struct dma_buf_map do not have to be cleaned up, but |
| 64 | * can be cleared to NULL with dma_buf_map_clear(). Cleared mappings | 64 | * can be cleared to NULL with dma_buf_map_clear(). Cleared mappings |
| @@ -458,8 +458,8 @@ void dma_resv_fini(struct dma_resv *obj); · 457 unmodified lines | |||
| 458 | int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences); | 458 | int dma_resv_reserve_shared(struct dma_resv *obj, unsigned int num_fences); |
| 459 | void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence); | 459 | void dma_resv_add_shared_fence(struct dma_resv *obj, struct dma_fence *fence); |
| 460 | void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); | 460 | void dma_resv_add_excl_fence(struct dma_resv *obj, struct dma_fence *fence); |
| 461 | int dma_resv_get_fences(struct dma_resv *obj, struct dma_fence **pfence_excl, | 461 | int dma_resv_get_fences(struct dma_resv *obj, bool write, |
| 462 | unsigned *pshared_count, struct dma_fence ***pshared); | 462 | unsigned int *num_fences, struct dma_fence ***fences); |
| 463 | int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); | 463 | int dma_resv_copy_fences(struct dma_resv *dst, struct dma_resv *src); |
| 464 | long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, | 464 | long dma_resv_wait_timeout(struct dma_resv *obj, bool wait_all, bool intr, |
| 465 | unsigned long timeout); | 465 | unsigned long timeout); |
| @@ -502,6 +502,7 @@ struct fb_info { · 501 unmodified lines | |||
| 502 | } *apertures; | 502 | } *apertures; |
| 503 | 503 | ||
| 504 | bool skip_vt_switch; /* no VT switch on suspend/resume required */ | 504 | bool skip_vt_switch; /* no VT switch on suspend/resume required */ |
| 505 | bool forced_out; /* set when being removed by another driver */ | ||
| 505 | }; | 506 | }; |
| 506 | 507 | ||
| 507 | static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { | 508 | static inline struct apertures_struct *alloc_apertures(unsigned int max_num) { |
| @@ -230,7 +230,7 @@ extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map * · 229 unmodified lines | |||
| 230 | do { \ | 230 | do { \ |
| 231 | typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ | 231 | typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ |
| 232 | _down_write_nest_lock(sem, &(nest_lock)->dep_map); \ | 232 | _down_write_nest_lock(sem, &(nest_lock)->dep_map); \ |
| 233 | } while (0); | 233 | } while (0) |
| 234 | 234 | ||
| 235 | /* | 235 | /* |
| 236 | * Take/release a lock when not the owner will release it. | 236 | * Take/release a lock when not the owner will release it. |
| @@ -91,6 +91,7 @@ enum rpi_firmware_property_tag { · 90 unmodified lines | |||
| 91 | RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, | 91 | RPI_FIRMWARE_GET_POE_HAT_VAL = 0x00030049, |
| 92 | RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, | 92 | RPI_FIRMWARE_SET_POE_HAT_VAL = 0x00030050, |
| 93 | RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, | 93 | RPI_FIRMWARE_NOTIFY_XHCI_RESET = 0x00030058, |
| 94 | RPI_FIRMWARE_NOTIFY_DISPLAY_DONE = 0x00030066, | ||
| 94 | 95 | ||
| 95 | /* Dispmanx TAGS */ | 96 | /* Dispmanx TAGS */ |
| 96 | RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, | 97 | RPI_FIRMWARE_FRAMEBUFFER_ALLOCATE = 0x00040001, |
| @@ -84,14 +84,14 @@ struct drm_panfrost_wait_bo { · 83 unmodified lines | |||
| 84 | __s64 timeout_ns; /* absolute */ | 84 | __s64 timeout_ns; /* absolute */ |
| 85 | }; | 85 | }; |
| 86 | 86 | ||
| 87 | /* Valid flags to pass to drm_panfrost_create_bo */ | ||
| 87 | #define PANFROST_BO_NOEXEC 1 | 88 | #define PANFROST_BO_NOEXEC 1 |
| 88 | #define PANFROST_BO_HEAP 2 | 89 | #define PANFROST_BO_HEAP 2 |
| 89 | 90 | ||
| 90 | /** | 91 | /** |
| 91 | * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. | 92 | * struct drm_panfrost_create_bo - ioctl argument for creating Panfrost BOs. |
| 92 | * | 93 | * |
| 93 | * There are currently no values for the flags argument, but it may be | 94 | * The flags argument is a bit mask of PANFROST_BO_* flags. |
| 94 | * used in a future extension. | ||
| 95 | */ | 95 | */ |
| 96 | struct drm_panfrost_create_bo { | 96 | struct drm_panfrost_create_bo { |
| 97 | __u32 size; | 97 | __u32 size; |