diff --git a/Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml b/Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml new file mode 100644 index 000000000000..862ef441ac9f --- /dev/null +++ b/Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/bridge/microchip,sam9x75-lvds.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Microchip SAM9X75 LVDS Controller + +maintainers: + - Dharma Balasubiramani + +description: + The Low Voltage Differential Signaling Controller (LVDSC) manages data + format conversion from the LCD Controller internal DPI bus to OpenLDI + LVDS output signals. LVDSC functions include bit mapping, balanced mode + management, and serializer. + +properties: + compatible: + const: microchip,sam9x75-lvds + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + items: + - description: Peripheral Bus Clock + + clock-names: + items: + - const: pclk + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + lvds-controller@f8060000 { + compatible = "microchip,sam9x75-lvds"; + reg = <0xf8060000 0x100>; + interrupts = <56 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&pmc PMC_TYPE_PERIPHERAL 56>; + clock-names = "pclk"; + }; diff --git a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml index d879c700594a..258dd9cfd770 100644 --- a/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml +++ b/Documentation/devicetree/bindings/display/bridge/toshiba,tc358775.yaml @@ -10,7 +10,7 @@ maintainers: - Vinay Simha BN description: | - This binding supports DSI to LVDS bridge TC358775 + This binding supports DSI to LVDS bridges TC358765 and TC358775 MIPI DSI-RX Data 4-lane, CLK 1-lane with data rates up to 800 Mbps/lane. Video frame size: @@ -21,7 +21,9 @@ description: | properties: compatible: - const: toshiba,tc358775 + enum: + - toshiba,tc358765 + - toshiba,tc358775 reg: maxItems: 1 @@ -46,11 +48,27 @@ properties: properties: port@0: - $ref: /schemas/graph.yaml#/properties/port + $ref: /schemas/graph.yaml#/$defs/port-base + unevaluatedProperties: false description: | DSI Input. The remote endpoint phandle should be a reference to a valid mipi_dsi_host device node. + properties: + endpoint: + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + + properties: + data-lanes: + description: array of physical DSI data lane indexes. + minItems: 1 + items: + - const: 1 + - const: 2 + - const: 3 + - const: 4 + port@1: $ref: /schemas/graph.yaml#/properties/port description: | @@ -70,10 +88,19 @@ required: - reg - vdd-supply - vddio-supply - - stby-gpios - reset-gpios - ports +allOf: + - if: + properties: + compatible: + contains: + const: toshiba,tc358765 + then: + properties: + stby-gpios: false + additionalProperties: false examples: @@ -108,6 +135,7 @@ examples: reg = <0>; d2l_in_test: endpoint { remote-endpoint = <&dsi0_out>; + data-lanes = <1 2 3 4>; }; }; @@ -132,7 +160,6 @@ examples: reg = <1>; dsi0_out: endpoint { remote-endpoint = <&d2l_in_test>; - data-lanes = <0 1 2 3>; }; }; }; @@ -167,6 +194,7 @@ examples: reg = <0>; d2l_in_dual: endpoint { remote-endpoint = <&dsi0_out_dual>; + data-lanes = <1 2 3 4>; }; }; @@ -198,7 +226,6 @@ examples: reg = <1>; dsi0_out_dual: endpoint { remote-endpoint = <&d2l_in_dual>; - data-lanes = <0 1 2 3>; }; }; }; diff --git a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml index d3abd7f4ebcd..db5acd2807ed 100644 --- a/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml +++ b/Documentation/devicetree/bindings/display/panel/panel-simple-dsi.yaml @@ -36,6 +36,8 @@ properties: - jdi,fhd-r63452 # Khadas TS050 5" 1080x1920 LCD panel - khadas,ts050 + # Khadas TS050 V2 5" 1080x1920 LCD panel + - khadas,ts050v2 # Kingdisplay KD097D04 9.7" 1536x2048 TFT LCD panel - kingdisplay,kd097d04 # LG ACX467AKM-7 4.95" 1080×1920 LCD Panel diff --git a/Documentation/devicetree/bindings/display/panel/raydium,rm69380.yaml b/Documentation/devicetree/bindings/display/panel/raydium,rm69380.yaml new file mode 100644 index 000000000000..b17765b2b351 --- /dev/null +++ b/Documentation/devicetree/bindings/display/panel/raydium,rm69380.yaml @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/display/panel/raydium,rm69380.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Raydium RM69380-based DSI display panels + +maintainers: + - David Wronek + +description: + The Raydium RM69380 is a generic DSI panel IC used to control + OLED panels. + +allOf: + - $ref: panel-common-dual.yaml# + +properties: + compatible: + items: + - enum: + - lenovo,j716f-edo-rm69380 + - const: raydium,rm69380 + description: This indicates the panel manufacturer of the panel + that is in turn using the RM69380 panel driver. The compatible + string determines how the RM69380 panel driver shall be configured + to work with the indicated panel. The raydium,rm69380 compatible shall + always be provided as a fallback. + + avdd-supply: + description: Analog voltage rail + + vddio-supply: + description: I/O voltage rail + + reset-gpios: + maxItems: 1 + description: phandle of gpio for reset line - This should be active low + + reg: true + +required: + - compatible + - reg + - avdd-supply + - vddio-supply + - reset-gpios + +unevaluatedProperties: false + +examples: + - | + #include + + dsi { + #address-cells = <1>; + #size-cells = <0>; + + panel@0 { + compatible = "lenovo,j716f-edo-rm69380", "raydium,rm69380"; + reg = <0>; + + avdd-supply = <&panel_avdd_regulator>; + vddio-supply = <&vreg_l14a>; + reset-gpios = <&tlmm 75 GPIO_ACTIVE_LOW>; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + port@0 { + reg = <0>; + panel_in_0: endpoint { + remote-endpoint = <&mdss_dsi0_out>; + }; + }; + + port@1 { + reg = <1>; + panel_in_1: endpoint { + remote-endpoint = <&mdss_dsi1_out>; + }; + }; + }; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml index af638b6c0d21..2aac62219ff6 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,dw-hdmi.yaml @@ -15,6 +15,7 @@ description: | allOf: - $ref: ../bridge/synopsys,dw-hdmi.yaml# + - $ref: /schemas/sound/dai-common.yaml# properties: compatible: @@ -124,6 +125,9 @@ properties: description: phandle to the GRF to mux vopl/vopb. + "#sound-dai-cells": + const: 0 + required: - compatible - reg @@ -153,6 +157,7 @@ examples: ddc-i2c-bus = <&i2c5>; power-domains = <&power RK3288_PD_VIO>; rockchip,grf = <&grf>; + #sound-dai-cells = <0>; ports { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml index be78dcfa1c76..5b87b0f1963e 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,inno-hdmi.yaml @@ -37,6 +37,9 @@ properties: power-domains: maxItems: 1 + "#sound-dai-cells": + const: 0 + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -66,6 +69,7 @@ required: - ports allOf: + - $ref: /schemas/sound/dai-common.yaml# - if: properties: compatible: @@ -106,6 +110,7 @@ examples: clock-names = "pclk"; pinctrl-names = "default"; pinctrl-0 = <&hdmi_ctl>; + #sound-dai-cells = <0>; ports { #address-cells = <1>; diff --git a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3066-hdmi.yaml b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3066-hdmi.yaml index 1a68a940d165..6d4b78a36576 100644 --- a/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3066-hdmi.yaml +++ b/Documentation/devicetree/bindings/display/rockchip/rockchip,rk3066-hdmi.yaml @@ -10,6 +10,9 @@ maintainers: - Sandy Huang - Heiko Stuebner +allOf: + - $ref: /schemas/sound/dai-common.yaml# + properties: compatible: const: rockchip,rk3066-hdmi @@ -34,6 +37,9 @@ properties: description: This soc uses GRF regs to switch the HDMI TX input between vop0 and vop1. + "#sound-dai-cells": + const: 0 + ports: $ref: /schemas/graph.yaml#/properties/ports @@ -83,6 +89,7 @@ examples: pinctrl-names = "default"; power-domains = <&power RK3066_PD_VIO>; rockchip,grf = <&grf>; + #sound-dai-cells = <0>; ports { #address-cells = <1>; diff --git a/MAINTAINERS b/MAINTAINERS index 68f680d9f147..d6327dc12cb1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14582,6 +14582,14 @@ S: Supported F: Documentation/devicetree/bindings/pwm/atmel,at91sam-pwm.yaml F: drivers/pwm/pwm-atmel.c +MICROCHIP SAM9x7-COMPATIBLE LVDS CONTROLLER +M: Manikandan Muralidharan +M: Dharma Balasubiramani +L: dri-devel@lists.freedesktop.org +S: Supported +F: Documentation/devicetree/bindings/display/bridge/microchip,sam9x75-lvds.yaml +F: drivers/gpu/drm/bridge/microchip-lvds.c + MICROCHIP SAMA5D2-COMPATIBLE ADC DRIVER M: Eugen Hristev L: linux-iio@vger.kernel.org diff --git a/drivers/accel/ivpu/ivpu_debugfs.c b/drivers/accel/ivpu/ivpu_debugfs.c index d09d29775b3f..e07e447d08d1 100644 --- a/drivers/accel/ivpu/ivpu_debugfs.c +++ b/drivers/accel/ivpu/ivpu_debugfs.c @@ -3,6 +3,8 @@ * Copyright (C) 2020-2023 Intel Corporation */ +#include + #include #include #include diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 92af057dbf6d..492aebc44e51 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -39,6 +39,7 @@ #include "amdgpu.h" #include "amdgpu_trace.h" #include "amdgpu_amdkfd.h" +#include "amdgpu_vram_mgr.h" /** * DOC: amdgpu_object @@ -601,8 +602,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, if (!amdgpu_bo_support_uswc(bo->flags)) bo->flags &= ~AMDGPU_GEM_CREATE_CPU_GTT_USWC; - if (adev->ras_enabled) - bo->flags |= AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE; + bo->flags |= AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE; bo->tbo.bdev = &adev->mman.bdev; if (bp->domain & (AMDGPU_GEM_DOMAIN_GWS | AMDGPU_GEM_DOMAIN_OA | @@ -633,7 +633,7 @@ int amdgpu_bo_create(struct amdgpu_device *adev, bo->tbo.resource->mem_type == TTM_PL_VRAM) { struct dma_fence *fence; - r = amdgpu_fill_buffer(bo, 0, bo->tbo.base.resv, &fence, true); + r = amdgpu_ttm_clear_buffer(bo, bo->tbo.base.resv, &fence); if (unlikely(r)) goto fail_unreserve; @@ -1366,8 +1366,9 @@ void amdgpu_bo_release_notify(struct ttm_buffer_object *bo) if (WARN_ON_ONCE(!dma_resv_trylock(bo->base.resv))) return; - r = amdgpu_fill_buffer(abo, AMDGPU_POISON, bo->base.resv, &fence, true); + r = amdgpu_fill_buffer(abo, 0, bo->base.resv, &fence, true); if (!WARN_ON(r)) { + amdgpu_vram_mgr_set_cleared(bo->resource); amdgpu_bo_fence(abo, fence, false); dma_fence_put(fence); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h index 381101d2bf05..50fcd86e1033 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_res_cursor.h @@ -164,4 +164,29 @@ static inline void amdgpu_res_next(struct amdgpu_res_cursor *cur, uint64_t size) } } +/** + * amdgpu_res_cleared - check if blocks are cleared + * + * @cur: the cursor to extract the block + * + * Check if the @cur block is cleared + */ +static inline bool amdgpu_res_cleared(struct amdgpu_res_cursor *cur) +{ + struct drm_buddy_block *block; + + switch (cur->mem_type) { + case TTM_PL_VRAM: + block = cur->node; + + if (!amdgpu_vram_mgr_is_cleared(block)) + return false; + break; + default: + return false; + } + + return true; +} + #endif diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 1d71729e3f6b..6b48bcf53ce9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -378,11 +378,12 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, (abo->flags & AMDGPU_GEM_CREATE_VRAM_WIPE_ON_RELEASE)) { struct dma_fence *wipe_fence = NULL; - r = amdgpu_fill_buffer(abo, AMDGPU_POISON, NULL, &wipe_fence, - false); + r = amdgpu_fill_buffer(abo, 0, NULL, &wipe_fence, + false); if (r) { goto error; } else if (wipe_fence) { + amdgpu_vram_mgr_set_cleared(bo->resource); dma_fence_put(fence); fence = wipe_fence; } @@ -2226,6 +2227,71 @@ static int amdgpu_ttm_fill_mem(struct amdgpu_ring *ring, uint32_t src_data, return 0; } +/** + * amdgpu_ttm_clear_buffer - clear memory buffers + * @bo: amdgpu buffer object + * @resv: reservation object + * @fence: dma_fence associated with the operation + * + * Clear the memory buffer resource. + * + * Returns: + * 0 for success or a negative error code on failure. + */ +int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo, + struct dma_resv *resv, + struct dma_fence **fence) +{ + struct amdgpu_device *adev = amdgpu_ttm_adev(bo->tbo.bdev); + struct amdgpu_ring *ring = adev->mman.buffer_funcs_ring; + struct amdgpu_res_cursor cursor; + u64 addr; + int r; + + if (!adev->mman.buffer_funcs_enabled) + return -EINVAL; + + if (!fence) + return -EINVAL; + + *fence = dma_fence_get_stub(); + + amdgpu_res_first(bo->tbo.resource, 0, amdgpu_bo_size(bo), &cursor); + + mutex_lock(&adev->mman.gtt_window_lock); + while (cursor.remaining) { + struct dma_fence *next = NULL; + u64 size; + + if (amdgpu_res_cleared(&cursor)) { + amdgpu_res_next(&cursor, cursor.size); + continue; + } + + /* Never clear more than 256MiB at once to avoid timeouts */ + size = min(cursor.size, 256ULL << 20); + + r = amdgpu_ttm_map_buffer(&bo->tbo, bo->tbo.resource, &cursor, + 1, ring, false, &size, &addr); + if (r) + goto err; + + r = amdgpu_ttm_fill_mem(ring, 0, addr, size, resv, + &next, true, true); + if (r) + goto err; + + dma_fence_put(*fence); + *fence = next; + + amdgpu_res_next(&cursor, size); + } +err: + mutex_unlock(&adev->mman.gtt_window_lock); + + return r; +} + int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t src_data, struct dma_resv *resv, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h index 32cf6b6f6efd..4f5e70ee9ad0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.h @@ -38,8 +38,6 @@ #define AMDGPU_GTT_MAX_TRANSFER_SIZE 512 #define AMDGPU_GTT_NUM_TRANSFER_WINDOWS 2 -#define AMDGPU_POISON 0xd0bed0be - extern const struct attribute_group amdgpu_vram_mgr_attr_group; extern const struct attribute_group amdgpu_gtt_mgr_attr_group; @@ -158,6 +156,9 @@ int amdgpu_ttm_copy_mem_to_mem(struct amdgpu_device *adev, uint64_t size, bool tmz, struct dma_resv *resv, struct dma_fence **f); +int amdgpu_ttm_clear_buffer(struct amdgpu_bo *bo, + struct dma_resv *resv, + struct dma_fence **fence); int amdgpu_fill_buffer(struct amdgpu_bo *bo, uint32_t src_data, struct dma_resv *resv, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c index 8db880244324..e494f5bf136a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.c @@ -450,6 +450,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, { struct amdgpu_vram_mgr *mgr = to_vram_mgr(man); struct amdgpu_device *adev = to_amdgpu_device(mgr); + struct amdgpu_bo *bo = ttm_to_amdgpu_bo(tbo); u64 vis_usage = 0, max_bytes, min_block_size; struct amdgpu_vram_mgr_resource *vres; u64 size, remaining_size, lpfn, fpfn; @@ -501,6 +502,9 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, if (place->flags & TTM_PL_FLAG_CONTIGUOUS) vres->flags |= DRM_BUDDY_CONTIGUOUS_ALLOCATION; + if (bo->flags & AMDGPU_GEM_CREATE_VRAM_CLEARED) + vres->flags |= DRM_BUDDY_CLEAR_ALLOCATION; + if (fpfn || lpfn != mgr->mm.size) /* Allocate blocks in desired range */ vres->flags |= DRM_BUDDY_RANGE_ALLOCATION; @@ -571,7 +575,7 @@ static int amdgpu_vram_mgr_new(struct ttm_resource_manager *man, return 0; error_free_blocks: - drm_buddy_free_list(mm, &vres->blocks); + drm_buddy_free_list(mm, &vres->blocks, 0); mutex_unlock(&mgr->lock); error_fini: ttm_resource_fini(man, &vres->base); @@ -604,7 +608,7 @@ static void amdgpu_vram_mgr_del(struct ttm_resource_manager *man, amdgpu_vram_mgr_do_reserve(man); - drm_buddy_free_list(mm, &vres->blocks); + drm_buddy_free_list(mm, &vres->blocks, vres->flags); mutex_unlock(&mgr->lock); atomic64_sub(vis_usage, &mgr->vis_usage); @@ -912,7 +916,7 @@ void amdgpu_vram_mgr_fini(struct amdgpu_device *adev) kfree(rsv); list_for_each_entry_safe(rsv, temp, &mgr->reserved_pages, blocks) { - drm_buddy_free_list(&mgr->mm, &rsv->allocated); + drm_buddy_free_list(&mgr->mm, &rsv->allocated, 0); kfree(rsv); } if (!adev->gmc.is_app_apu) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h index 0e04e42cf809..b256cbc2bc27 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vram_mgr.h @@ -53,10 +53,20 @@ static inline u64 amdgpu_vram_mgr_block_size(struct drm_buddy_block *block) return (u64)PAGE_SIZE << drm_buddy_block_order(block); } +static inline bool amdgpu_vram_mgr_is_cleared(struct drm_buddy_block *block) +{ + return drm_buddy_block_is_clear(block); +} + static inline struct amdgpu_vram_mgr_resource * to_amdgpu_vram_mgr_resource(struct ttm_resource *res) { return container_of(res, struct amdgpu_vram_mgr_resource, base); } +static inline void amdgpu_vram_mgr_set_cleared(struct ttm_resource *res) +{ + to_amdgpu_vram_mgr_resource(res)->flags |= DRM_BUDDY_CLEARED; +} + #endif diff --git a/drivers/gpu/drm/armada/armada_debugfs.c b/drivers/gpu/drm/armada/armada_debugfs.c index 29f4b52e3c8d..a763349dd89f 100644 --- a/drivers/gpu/drm/armada/armada_debugfs.c +++ b/drivers/gpu/drm/armada/armada_debugfs.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig index d1fbf8796fea..30a17876ff50 100644 --- a/drivers/gpu/drm/bridge/Kconfig +++ b/drivers/gpu/drm/bridge/Kconfig @@ -189,6 +189,13 @@ config DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW to DP++. This is used with the i.MX6 imx-ldb driver. You are likely to say N here. +config DRM_MICROCHIP_LVDS_SERIALIZER + tristate "Microchip LVDS serializer support" + depends on OF + depends on DRM_ATMEL_HLCDC + help + Support for Microchip's LVDS serializer. + config DRM_NWL_MIPI_DSI tristate "Northwest Logic MIPI DSI Host controller" depends on DRM diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile index 017b5832733b..7df87b582dca 100644 --- a/drivers/gpu/drm/bridge/Makefile +++ b/drivers/gpu/drm/bridge/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_DRM_LONTIUM_LT9611) += lontium-lt9611.o obj-$(CONFIG_DRM_LONTIUM_LT9611UXC) += lontium-lt9611uxc.o obj-$(CONFIG_DRM_LVDS_CODEC) += lvds-codec.o obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o +obj-$(CONFIG_DRM_MICROCHIP_LVDS_SERIALIZER) += microchip-lvds.o obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o obj-$(CONFIG_DRM_PARADE_PS8640) += parade-ps8640.o diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511.h b/drivers/gpu/drm/bridge/adv7511/adv7511.h index 39c9ece373b0..ea271f62b214 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511.h +++ b/drivers/gpu/drm/bridge/adv7511/adv7511.h @@ -356,6 +356,7 @@ struct adv7511 { enum drm_connector_status status; bool powered; + struct drm_bridge *next_bridge; struct drm_display_mode curr_mode; unsigned int f_tmds; diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c index f3b4616a8fb6..dd21b81bd28f 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -951,6 +952,12 @@ static int adv7511_bridge_attach(struct drm_bridge *bridge, struct adv7511 *adv = bridge_to_adv7511(bridge); int ret = 0; + if (adv->next_bridge) { + ret = drm_bridge_attach(bridge->encoder, adv->next_bridge, bridge, flags); + if (ret) + return ret; + } + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { ret = adv7511_connector_init(adv); if (ret < 0) @@ -1221,6 +1228,11 @@ static int adv7511_probe(struct i2c_client *i2c) memset(&link_config, 0, sizeof(link_config)); + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, -1, NULL, + &adv7511->next_bridge); + if (ret && ret != -ENODEV) + return ret; + if (adv7511->info->link_config) ret = adv7511_parse_dt(dev->of_node, &link_config); else diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index ff3284b6b1a3..9eecac457dcf 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -781,7 +781,6 @@ static struct mipi_dsi_driver chipone_dsi_driver = { .remove = chipone_dsi_remove, .driver = { .name = "chipone-icn6211", - .owner = THIS_MODULE, .of_match_table = chipone_of_match, }, }; diff --git a/drivers/gpu/drm/bridge/imx/Kconfig b/drivers/gpu/drm/bridge/imx/Kconfig index 7687ed652df5..13142a6b8590 100644 --- a/drivers/gpu/drm/bridge/imx/Kconfig +++ b/drivers/gpu/drm/bridge/imx/Kconfig @@ -8,8 +8,8 @@ config DRM_IMX8MP_DW_HDMI_BRIDGE depends on COMMON_CLK depends on DRM_DW_HDMI depends on OF - select DRM_IMX8MP_HDMI_PVI - select PHY_FSL_SAMSUNG_HDMI_PHY + imply DRM_IMX8MP_HDMI_PVI + imply PHY_FSL_SAMSUNG_HDMI_PHY help Choose this to enable support for the internal HDMI encoder found on the i.MX8MP SoC. diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index 27334173e911..3f68c82888c2 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -3,6 +3,7 @@ * Copyright (c) 2020, The Linux Foundation. All rights reserved. */ #include +#include #include #include #include diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c new file mode 100644 index 000000000000..b8313dad6072 --- /dev/null +++ b/drivers/gpu/drm/bridge/microchip-lvds.c @@ -0,0 +1,229 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2023 Microchip Technology Inc. and its subsidiaries + * + * Author: Manikandan Muralidharan + * Author: Dharma Balasubiramani + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define LVDS_POLL_TIMEOUT_MS 1000 + +/* LVDSC register offsets */ +#define LVDSC_CR 0x00 +#define LVDSC_CFGR 0x04 +#define LVDSC_SR 0x0C +#define LVDSC_WPMR 0xE4 + +/* Bitfields in LVDSC_CR (Control Register) */ +#define LVDSC_CR_SER_EN BIT(0) + +/* Bitfields in LVDSC_CFGR (Configuration Register) */ +#define LVDSC_CFGR_PIXSIZE_24BITS 0 +#define LVDSC_CFGR_DEN_POL_HIGH 0 +#define LVDSC_CFGR_DC_UNBALANCED 0 +#define LVDSC_CFGR_MAPPING_JEIDA BIT(6) + +/*Bitfields in LVDSC_SR */ +#define LVDSC_SR_CS BIT(0) + +/* Bitfields in LVDSC_WPMR (Write Protection Mode Register) */ +#define LVDSC_WPMR_WPKEY_MASK GENMASK(31, 8) +#define LVDSC_WPMR_WPKEY_PSSWD 0x4C5644 + +struct mchp_lvds { + struct device *dev; + void __iomem *regs; + struct clk *pclk; + struct drm_panel *panel; + struct drm_bridge bridge; + struct drm_bridge *panel_bridge; +}; + +static inline struct mchp_lvds *bridge_to_lvds(struct drm_bridge *bridge) +{ + return container_of(bridge, struct mchp_lvds, bridge); +} + +static inline u32 lvds_readl(struct mchp_lvds *lvds, u32 offset) +{ + return readl_relaxed(lvds->regs + offset); +} + +static inline void lvds_writel(struct mchp_lvds *lvds, u32 offset, u32 val) +{ + writel_relaxed(val, lvds->regs + offset); +} + +static void lvds_serialiser_on(struct mchp_lvds *lvds) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(LVDS_POLL_TIMEOUT_MS); + + /* The LVDSC registers can only be written if WPEN is cleared */ + lvds_writel(lvds, LVDSC_WPMR, (LVDSC_WPMR_WPKEY_PSSWD & + LVDSC_WPMR_WPKEY_MASK)); + + /* Wait for the status of configuration registers to be changed */ + while (lvds_readl(lvds, LVDSC_SR) & LVDSC_SR_CS) { + if (time_after(jiffies, timeout)) { + dev_err(lvds->dev, "%s: timeout error\n", __func__); + return; + } + usleep_range(1000, 2000); + } + + /* Configure the LVDSC */ + lvds_writel(lvds, LVDSC_CFGR, (LVDSC_CFGR_MAPPING_JEIDA | + LVDSC_CFGR_DC_UNBALANCED | + LVDSC_CFGR_DEN_POL_HIGH | + LVDSC_CFGR_PIXSIZE_24BITS)); + + /* Enable the LVDS serializer */ + lvds_writel(lvds, LVDSC_CR, LVDSC_CR_SER_EN); +} + +static int mchp_lvds_attach(struct drm_bridge *bridge, + enum drm_bridge_attach_flags flags) +{ + struct mchp_lvds *lvds = bridge_to_lvds(bridge); + + return drm_bridge_attach(bridge->encoder, lvds->panel_bridge, + bridge, flags); +} + +static void mchp_lvds_enable(struct drm_bridge *bridge) +{ + struct mchp_lvds *lvds = bridge_to_lvds(bridge); + int ret; + + ret = clk_prepare_enable(lvds->pclk); + if (ret < 0) { + dev_err(lvds->dev, "failed to enable lvds pclk %d\n", ret); + return; + } + + ret = pm_runtime_get_sync(lvds->dev); + if (ret < 0) { + dev_err(lvds->dev, "failed to get pm runtime: %d\n", ret); + return; + } + + lvds_serialiser_on(lvds); +} + +static void mchp_lvds_disable(struct drm_bridge *bridge) +{ + struct mchp_lvds *lvds = bridge_to_lvds(bridge); + + pm_runtime_put(lvds->dev); + clk_disable_unprepare(lvds->pclk); +} + +static const struct drm_bridge_funcs mchp_lvds_bridge_funcs = { + .attach = mchp_lvds_attach, + .enable = mchp_lvds_enable, + .disable = mchp_lvds_disable, +}; + +static int mchp_lvds_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mchp_lvds *lvds; + struct device_node *port; + int ret; + + if (!dev->of_node) + return -ENODEV; + + lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); + if (!lvds) + return -ENOMEM; + + lvds->dev = dev; + + lvds->regs = devm_ioremap_resource(lvds->dev, + platform_get_resource(pdev, IORESOURCE_MEM, 0)); + if (IS_ERR(lvds->regs)) + return PTR_ERR(lvds->regs); + + lvds->pclk = devm_clk_get(lvds->dev, "pclk"); + if (IS_ERR(lvds->pclk)) + return dev_err_probe(lvds->dev, PTR_ERR(lvds->pclk), + "could not get pclk_lvds\n"); + + port = of_graph_get_remote_node(dev->of_node, 1, 0); + if (!port) { + dev_err(dev, + "can't find port point, please init lvds panel port!\n"); + return -ENODEV; + } + + lvds->panel = of_drm_find_panel(port); + of_node_put(port); + + if (IS_ERR(lvds->panel)) + return -EPROBE_DEFER; + + lvds->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, 1, 0); + + if (IS_ERR(lvds->panel_bridge)) + return PTR_ERR(lvds->panel_bridge); + + lvds->bridge.of_node = dev->of_node; + lvds->bridge.type = DRM_MODE_CONNECTOR_LVDS; + lvds->bridge.funcs = &mchp_lvds_bridge_funcs; + + dev_set_drvdata(dev, lvds); + ret = devm_pm_runtime_enable(dev); + if (ret < 0) { + dev_err(lvds->dev, "failed to enable pm runtime: %d\n", ret); + return ret; + } + + drm_bridge_add(&lvds->bridge); + + return 0; +} + +static const struct of_device_id mchp_lvds_dt_ids[] = { + { + .compatible = "microchip,sam9x75-lvds", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, mchp_lvds_dt_ids); + +static struct platform_driver mchp_lvds_driver = { + .probe = mchp_lvds_probe, + .driver = { + .name = "microchip-lvds", + .of_match_table = mchp_lvds_dt_ids, + }, +}; +module_platform_driver(mchp_lvds_driver); + +MODULE_AUTHOR("Manikandan Muralidharan "); +MODULE_AUTHOR("Dharma Balasubiramani "); +MODULE_DESCRIPTION("Low Voltage Differential Signaling Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c index 7f41525f7a6e..32506524d9a2 100644 --- a/drivers/gpu/drm/bridge/panel.c +++ b/drivers/gpu/drm/bridge/panel.c @@ -4,6 +4,8 @@ * Copyright (C) 2017 Broadcom */ +#include + #include #include #include diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c index deccb3995022..3d3d135b4348 100644 --- a/drivers/gpu/drm/bridge/tc358764.c +++ b/drivers/gpu/drm/bridge/tc358764.c @@ -401,7 +401,6 @@ static struct mipi_dsi_driver tc358764_driver = { .remove = tc358764_remove, .driver = { .name = "tc358764", - .owner = THIS_MODULE, .of_match_table = tc358764_of_match, }, }; diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c index fea4f00a20f8..3b7cc3be2ccd 100644 --- a/drivers/gpu/drm/bridge/tc358775.c +++ b/drivers/gpu/drm/bridge/tc358775.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -107,6 +108,7 @@ #define RDPKTLN 0x0404 /* Command Read Packet Length */ #define VPCTRL 0x0450 /* Video Path Control */ +#define EVTMODE BIT(5) /* Video event mode enable, tc35876x only */ #define HTIM1 0x0454 /* Horizontal Timing Control 1 */ #define HTIM2 0x0458 /* Horizontal Timing Control 2 */ #define VTIM1 0x045C /* Vertical Timing Control 1 */ @@ -254,6 +256,11 @@ enum tc358775_ports { TC358775_LVDS_OUT1, }; +enum tc3587x5_type { + TC358765 = 0x65, + TC358775 = 0x75, +}; + struct tc_data { struct i2c_client *i2c; struct device *dev; @@ -271,6 +278,8 @@ struct tc_data { struct gpio_desc *stby_gpio; u8 lvds_link; /* single-link or dual-link */ u8 bpc; + + enum tc3587x5_type type; }; static inline struct tc_data *bridge_to_tc(struct drm_bridge *b) @@ -424,10 +433,16 @@ static void tc_bridge_enable(struct drm_bridge *bridge) d2l_write(tc->i2c, PPI_STARTPPI, PPI_START_FUNCTION); d2l_write(tc->i2c, DSI_STARTDSI, DSI_RX_START); + /* Video event mode vs pulse mode bit, does not exist for tc358775 */ + if (tc->type == TC358765) + val = EVTMODE; + else + val = 0; + if (tc->bpc == 8) - val = TC358775_VPCTRL_OPXLFMT(1); + val |= TC358775_VPCTRL_OPXLFMT(1); else /* bpc = 6; */ - val = TC358775_VPCTRL_MSF(1); + val |= TC358775_VPCTRL_MSF(1); dsiclk = mode->crtc_clock * 3 * tc->bpc / tc->num_dsi_lanes / 1000; clkdiv = dsiclk / (tc->lvds_link == DUAL_LINK ? DIVIDE_BY_6 : DIVIDE_BY_3); @@ -454,10 +469,6 @@ static void tc_bridge_enable(struct drm_bridge *bridge) dev_dbg(tc->dev, "bus_formats %04x bpc %d\n", connector->display_info.bus_formats[0], tc->bpc); - /* - * Default hardware register settings of tc358775 configured - * with MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA jeida-24 format - */ if (connector->display_info.bus_formats[0] == MEDIA_BUS_FMT_RGB888_1X7X4_SPWG) { /* VESA-24 */ @@ -468,14 +479,15 @@ static void tc_bridge_enable(struct drm_bridge *bridge) d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B6, LVI_B7, LVI_B1, LVI_B2)); d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R6)); - } else { /* MEDIA_BUS_FMT_RGB666_1X7X3_SPWG - JEIDA-18 */ - d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R0, LVI_R1, LVI_R2, LVI_R3)); - d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R4, LVI_L0, LVI_R5, LVI_G0)); - d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G1, LVI_G2, LVI_L0, LVI_L0)); - d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G3, LVI_G4, LVI_G5, LVI_B0)); - d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_L0, LVI_L0, LVI_B1, LVI_B2)); - d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B3, LVI_B4, LVI_B5, LVI_L0)); - d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_L0)); + } else { + /* JEIDA-18 and JEIDA-24 */ + d2l_write(tc->i2c, LV_MX0003, LV_MX(LVI_R2, LVI_R3, LVI_R4, LVI_R5)); + d2l_write(tc->i2c, LV_MX0407, LV_MX(LVI_R6, LVI_R1, LVI_R7, LVI_G2)); + d2l_write(tc->i2c, LV_MX0811, LV_MX(LVI_G3, LVI_G4, LVI_G0, LVI_G1)); + d2l_write(tc->i2c, LV_MX1215, LV_MX(LVI_G5, LVI_G6, LVI_G7, LVI_B2)); + d2l_write(tc->i2c, LV_MX1619, LV_MX(LVI_B0, LVI_B1, LVI_B3, LVI_B4)); + d2l_write(tc->i2c, LV_MX2023, LV_MX(LVI_B5, LVI_B6, LVI_B7, LVI_L0)); + d2l_write(tc->i2c, LV_MX2427, LV_MX(LVI_HS, LVI_VS, LVI_DE, LVI_R0)); } d2l_write(tc->i2c, VFUEN, VFUEN_EN); @@ -528,27 +540,24 @@ tc_mode_valid(struct drm_bridge *bridge, static int tc358775_parse_dt(struct device_node *np, struct tc_data *tc) { struct device_node *endpoint; - struct device_node *parent; struct device_node *remote; int dsi_lanes = -1; - /* - * To get the data-lanes of dsi, we need to access the dsi0_out of port1 - * of dsi0 endpoint from bridge port0 of d2l_in - */ endpoint = of_graph_get_endpoint_by_regs(tc->dev->of_node, TC358775_DSI_IN, -1); - if (endpoint) { - /* dsi0_out node */ - parent = of_graph_get_remote_port_parent(endpoint); - of_node_put(endpoint); - if (parent) { - /* dsi0 port 1 */ - dsi_lanes = drm_of_get_data_lanes_count_ep(parent, 1, -1, 1, 4); - of_node_put(parent); - } + dsi_lanes = drm_of_get_data_lanes_count(endpoint, 1, 4); + + /* Quirk old dtb: Use data lanes from the DSI host side instead of bridge */ + if (dsi_lanes == -EINVAL || dsi_lanes == -ENODEV) { + remote = of_graph_get_remote_endpoint(endpoint); + dsi_lanes = drm_of_get_data_lanes_count(remote, 1, 4); + of_node_put(remote); + if (dsi_lanes >= 1) + dev_warn(tc->dev, "no dsi-lanes for the bridge, using host lanes\n"); } + of_node_put(endpoint); + if (dsi_lanes < 0) return dsi_lanes; @@ -623,7 +632,21 @@ static int tc_attach_host(struct tc_data *tc) dsi->lanes = tc->num_dsi_lanes; dsi->format = MIPI_DSI_FMT_RGB888; - dsi->mode_flags = MIPI_DSI_MODE_VIDEO; + dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM; + + /* + * The hs_rate and lp_rate are data rate values. The HS mode is + * differential, while the LP mode is single ended. As the HS mode + * uses DDR, the DSI clock frequency is half the hs_rate. The 10 Mbs + * data rate for LP mode is not specified in the bridge data sheet, + * but seems to be part of the MIPI DSI spec. + */ + if (tc->type == TC358765) + dsi->hs_rate = 800000000; + else + dsi->hs_rate = 1000000000; + dsi->lp_rate = 10000000; ret = devm_mipi_dsi_attach(dev, dsi); if (ret < 0) { @@ -646,6 +669,7 @@ static int tc_probe(struct i2c_client *client) tc->dev = dev; tc->i2c = client; + tc->type = (enum tc3587x5_type)(unsigned long)of_device_get_match_data(dev); tc->panel_bridge = devm_drm_of_get_bridge(dev, dev->of_node, TC358775_LVDS_OUT0, 0); @@ -670,12 +694,9 @@ static int tc_probe(struct i2c_client *client) return ret; } - tc->stby_gpio = devm_gpiod_get(dev, "stby", GPIOD_OUT_HIGH); - if (IS_ERR(tc->stby_gpio)) { - ret = PTR_ERR(tc->stby_gpio); - dev_err(dev, "cannot get stby-gpio %d\n", ret); - return ret; - } + tc->stby_gpio = devm_gpiod_get_optional(dev, "stby", GPIOD_OUT_HIGH); + if (IS_ERR(tc->stby_gpio)) + return PTR_ERR(tc->stby_gpio); tc->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(tc->reset_gpio)) { @@ -686,6 +707,7 @@ static int tc_probe(struct i2c_client *client) tc->bridge.funcs = &tc_bridge_funcs; tc->bridge.of_node = dev->of_node; + tc->bridge.pre_enable_prev_first = true; drm_bridge_add(&tc->bridge); i2c_set_clientdata(client, tc); @@ -709,13 +731,15 @@ static void tc_remove(struct i2c_client *client) } static const struct i2c_device_id tc358775_i2c_ids[] = { - { "tc358775", 0 }, + { "tc358765", TC358765, }, + { "tc358775", TC358775, }, { } }; MODULE_DEVICE_TABLE(i2c, tc358775_i2c_ids); static const struct of_device_id tc358775_of_ids[] = { - { .compatible = "toshiba,tc358775", }, + { .compatible = "toshiba,tc358765", .data = (void *)TC358765, }, + { .compatible = "toshiba,tc358775", .data = (void *)TC358775, }, { } }; MODULE_DEVICE_TABLE(of, tc358775_of_ids); diff --git a/drivers/gpu/drm/drm_buddy.c b/drivers/gpu/drm/drm_buddy.c index 5ebdd6f8f36e..284ebae71cc4 100644 --- a/drivers/gpu/drm/drm_buddy.c +++ b/drivers/gpu/drm/drm_buddy.c @@ -57,6 +57,16 @@ static void list_insert_sorted(struct drm_buddy *mm, __list_add(&block->link, node->link.prev, &node->link); } +static void clear_reset(struct drm_buddy_block *block) +{ + block->header &= ~DRM_BUDDY_HEADER_CLEAR; +} + +static void mark_cleared(struct drm_buddy_block *block) +{ + block->header |= DRM_BUDDY_HEADER_CLEAR; +} + static void mark_allocated(struct drm_buddy_block *block) { block->header &= ~DRM_BUDDY_HEADER_STATE; @@ -82,6 +92,133 @@ static void mark_split(struct drm_buddy_block *block) list_del(&block->link); } +static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) +{ + return s1 <= e2 && e1 >= s2; +} + +static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) +{ + return s1 <= s2 && e1 >= e2; +} + +static struct drm_buddy_block * +__get_buddy(struct drm_buddy_block *block) +{ + struct drm_buddy_block *parent; + + parent = block->parent; + if (!parent) + return NULL; + + if (parent->left == block) + return parent->right; + + return parent->left; +} + +static unsigned int __drm_buddy_free(struct drm_buddy *mm, + struct drm_buddy_block *block, + bool force_merge) +{ + struct drm_buddy_block *parent; + unsigned int order; + + while ((parent = block->parent)) { + struct drm_buddy_block *buddy; + + buddy = __get_buddy(block); + + if (!drm_buddy_block_is_free(buddy)) + break; + + if (!force_merge) { + /* + * Check the block and its buddy clear state and exit + * the loop if they both have the dissimilar state. + */ + if (drm_buddy_block_is_clear(block) != + drm_buddy_block_is_clear(buddy)) + break; + + if (drm_buddy_block_is_clear(block)) + mark_cleared(parent); + } + + list_del(&buddy->link); + if (force_merge && drm_buddy_block_is_clear(buddy)) + mm->clear_avail -= drm_buddy_block_size(mm, buddy); + + drm_block_free(mm, block); + drm_block_free(mm, buddy); + + block = parent; + } + + order = drm_buddy_block_order(block); + mark_free(mm, block); + + return order; +} + +static int __force_merge(struct drm_buddy *mm, + u64 start, + u64 end, + unsigned int min_order) +{ + unsigned int order; + int i; + + if (!min_order) + return -ENOMEM; + + if (min_order > mm->max_order) + return -EINVAL; + + for (i = min_order - 1; i >= 0; i--) { + struct drm_buddy_block *block, *prev; + + list_for_each_entry_safe_reverse(block, prev, &mm->free_list[i], link) { + struct drm_buddy_block *buddy; + u64 block_start, block_end; + + if (!block->parent) + continue; + + block_start = drm_buddy_block_offset(block); + block_end = block_start + drm_buddy_block_size(mm, block) - 1; + + if (!contains(start, end, block_start, block_end)) + continue; + + buddy = __get_buddy(block); + if (!drm_buddy_block_is_free(buddy)) + continue; + + WARN_ON(drm_buddy_block_is_clear(block) == + drm_buddy_block_is_clear(buddy)); + + /* + * If the prev block is same as buddy, don't access the + * block in the next iteration as we would free the + * buddy block as part of the free function. + */ + if (prev == buddy) + prev = list_prev_entry(prev, link); + + list_del(&block->link); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); + + order = __drm_buddy_free(mm, block, true); + if (order >= min_order) + return 0; + } + } + + return -ENOMEM; +} + /** * drm_buddy_init - init memory manager * @@ -186,11 +323,21 @@ EXPORT_SYMBOL(drm_buddy_init); */ void drm_buddy_fini(struct drm_buddy *mm) { + u64 root_size, size; + unsigned int order; int i; + size = mm->size; + for (i = 0; i < mm->n_roots; ++i) { + order = ilog2(size) - ilog2(mm->chunk_size); + __force_merge(mm, 0, size, order); + WARN_ON(!drm_buddy_block_is_free(mm->roots[i])); drm_block_free(mm, mm->roots[i]); + + root_size = mm->chunk_size << order; + size -= root_size; } WARN_ON(mm->avail != mm->size); @@ -223,26 +370,17 @@ static int split_block(struct drm_buddy *mm, mark_free(mm, block->left); mark_free(mm, block->right); + if (drm_buddy_block_is_clear(block)) { + mark_cleared(block->left); + mark_cleared(block->right); + clear_reset(block); + } + mark_split(block); return 0; } -static struct drm_buddy_block * -__get_buddy(struct drm_buddy_block *block) -{ - struct drm_buddy_block *parent; - - parent = block->parent; - if (!parent) - return NULL; - - if (parent->left == block) - return parent->right; - - return parent->left; -} - /** * drm_get_buddy - get buddy address * @@ -260,30 +398,6 @@ drm_get_buddy(struct drm_buddy_block *block) } EXPORT_SYMBOL(drm_get_buddy); -static void __drm_buddy_free(struct drm_buddy *mm, - struct drm_buddy_block *block) -{ - struct drm_buddy_block *parent; - - while ((parent = block->parent)) { - struct drm_buddy_block *buddy; - - buddy = __get_buddy(block); - - if (!drm_buddy_block_is_free(buddy)) - break; - - list_del(&buddy->link); - - drm_block_free(mm, block); - drm_block_free(mm, buddy); - - block = parent; - } - - mark_free(mm, block); -} - /** * drm_buddy_free_block - free a block * @@ -295,42 +409,74 @@ void drm_buddy_free_block(struct drm_buddy *mm, { BUG_ON(!drm_buddy_block_is_allocated(block)); mm->avail += drm_buddy_block_size(mm, block); - __drm_buddy_free(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail += drm_buddy_block_size(mm, block); + + __drm_buddy_free(mm, block, false); } EXPORT_SYMBOL(drm_buddy_free_block); +static void __drm_buddy_free_list(struct drm_buddy *mm, + struct list_head *objects, + bool mark_clear, + bool mark_dirty) +{ + struct drm_buddy_block *block, *on; + + WARN_ON(mark_dirty && mark_clear); + + list_for_each_entry_safe(block, on, objects, link) { + if (mark_clear) + mark_cleared(block); + else if (mark_dirty) + clear_reset(block); + drm_buddy_free_block(mm, block); + cond_resched(); + } + INIT_LIST_HEAD(objects); +} + +static void drm_buddy_free_list_internal(struct drm_buddy *mm, + struct list_head *objects) +{ + /* + * Don't touch the clear/dirty bit, since allocation is still internal + * at this point. For example we might have just failed part of the + * allocation. + */ + __drm_buddy_free_list(mm, objects, false, false); +} + /** * drm_buddy_free_list - free blocks * * @mm: DRM buddy manager * @objects: input list head to free blocks + * @flags: optional flags like DRM_BUDDY_CLEARED */ -void drm_buddy_free_list(struct drm_buddy *mm, struct list_head *objects) +void drm_buddy_free_list(struct drm_buddy *mm, + struct list_head *objects, + unsigned int flags) { - struct drm_buddy_block *block, *on; + bool mark_clear = flags & DRM_BUDDY_CLEARED; - list_for_each_entry_safe(block, on, objects, link) { - drm_buddy_free_block(mm, block); - cond_resched(); - } - INIT_LIST_HEAD(objects); + __drm_buddy_free_list(mm, objects, mark_clear, !mark_clear); } EXPORT_SYMBOL(drm_buddy_free_list); -static inline bool overlaps(u64 s1, u64 e1, u64 s2, u64 e2) +static bool block_incompatible(struct drm_buddy_block *block, unsigned int flags) { - return s1 <= e2 && e1 >= s2; -} + bool needs_clear = flags & DRM_BUDDY_CLEAR_ALLOCATION; -static inline bool contains(u64 s1, u64 e1, u64 s2, u64 e2) -{ - return s1 <= s2 && e1 >= e2; + return needs_clear != drm_buddy_block_is_clear(block); } static struct drm_buddy_block * -alloc_range_bias(struct drm_buddy *mm, - u64 start, u64 end, - unsigned int order) +__alloc_range_bias(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order, + unsigned long flags, + bool fallback) { u64 req_size = mm->chunk_size << order; struct drm_buddy_block *block; @@ -379,6 +525,9 @@ alloc_range_bias(struct drm_buddy *mm, if (contains(start, end, block_start, block_end) && order == drm_buddy_block_order(block)) { + if (!fallback && block_incompatible(block, flags)) + continue; + /* * Find the free block within the range. */ @@ -410,30 +559,57 @@ alloc_range_bias(struct drm_buddy *mm, if (buddy && (drm_buddy_block_is_free(block) && drm_buddy_block_is_free(buddy))) - __drm_buddy_free(mm, block); + __drm_buddy_free(mm, block, false); return ERR_PTR(err); } static struct drm_buddy_block * -get_maxblock(struct drm_buddy *mm, unsigned int order) +__drm_buddy_alloc_range_bias(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order, + unsigned long flags) { - struct drm_buddy_block *max_block = NULL, *node; + struct drm_buddy_block *block; + bool fallback = false; + + block = __alloc_range_bias(mm, start, end, order, + flags, fallback); + if (IS_ERR(block) && mm->clear_avail) + return __alloc_range_bias(mm, start, end, order, + flags, !fallback); + + return block; +} + +static struct drm_buddy_block * +get_maxblock(struct drm_buddy *mm, unsigned int order, + unsigned long flags) +{ + struct drm_buddy_block *max_block = NULL, *block = NULL; unsigned int i; for (i = order; i <= mm->max_order; ++i) { - if (!list_empty(&mm->free_list[i])) { - node = list_last_entry(&mm->free_list[i], - struct drm_buddy_block, - link); - if (!max_block) { - max_block = node; - continue; - } + struct drm_buddy_block *tmp_block; - if (drm_buddy_block_offset(node) > - drm_buddy_block_offset(max_block)) { - max_block = node; - } + list_for_each_entry_reverse(tmp_block, &mm->free_list[i], link) { + if (block_incompatible(tmp_block, flags)) + continue; + + block = tmp_block; + break; + } + + if (!block) + continue; + + if (!max_block) { + max_block = block; + continue; + } + + if (drm_buddy_block_offset(block) > + drm_buddy_block_offset(max_block)) { + max_block = block; } } @@ -450,11 +626,29 @@ alloc_from_freelist(struct drm_buddy *mm, int err; if (flags & DRM_BUDDY_TOPDOWN_ALLOCATION) { - block = get_maxblock(mm, order); + block = get_maxblock(mm, order, flags); if (block) /* Store the obtained block order */ tmp = drm_buddy_block_order(block); } else { + for (tmp = order; tmp <= mm->max_order; ++tmp) { + struct drm_buddy_block *tmp_block; + + list_for_each_entry_reverse(tmp_block, &mm->free_list[tmp], link) { + if (block_incompatible(tmp_block, flags)) + continue; + + block = tmp_block; + break; + } + + if (block) + break; + } + } + + if (!block) { + /* Fallback method */ for (tmp = order; tmp <= mm->max_order; ++tmp) { if (!list_empty(&mm->free_list[tmp])) { block = list_last_entry(&mm->free_list[tmp], @@ -464,10 +658,10 @@ alloc_from_freelist(struct drm_buddy *mm, break; } } - } - if (!block) - return ERR_PTR(-ENOSPC); + if (!block) + return ERR_PTR(-ENOSPC); + } BUG_ON(!drm_buddy_block_is_free(block)); @@ -483,7 +677,7 @@ alloc_from_freelist(struct drm_buddy *mm, err_undo: if (tmp != order) - __drm_buddy_free(mm, block); + __drm_buddy_free(mm, block, false); return ERR_PTR(err); } @@ -526,16 +720,18 @@ static int __alloc_range(struct drm_buddy *mm, } if (contains(start, end, block_start, block_end)) { - if (!drm_buddy_block_is_free(block)) { + if (drm_buddy_block_is_free(block)) { + mark_allocated(block); + total_allocated += drm_buddy_block_size(mm, block); + mm->avail -= drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); + list_add_tail(&block->link, &allocated); + continue; + } else if (!mm->clear_avail) { err = -ENOSPC; goto err_free; } - - mark_allocated(block); - total_allocated += drm_buddy_block_size(mm, block); - mm->avail -= drm_buddy_block_size(mm, block); - list_add_tail(&block->link, &allocated); - continue; } if (!drm_buddy_block_is_split(block)) { @@ -567,14 +763,14 @@ static int __alloc_range(struct drm_buddy *mm, if (buddy && (drm_buddy_block_is_free(block) && drm_buddy_block_is_free(buddy))) - __drm_buddy_free(mm, block); + __drm_buddy_free(mm, block, false); err_free: if (err == -ENOSPC && total_allocated_on_err) { list_splice_tail(&allocated, blocks); *total_allocated_on_err = total_allocated; } else { - drm_buddy_free_list(mm, &allocated); + drm_buddy_free_list_internal(mm, &allocated); } return err; @@ -640,11 +836,11 @@ static int __alloc_contig_try_harder(struct drm_buddy *mm, list_splice(&blocks_lhs, blocks); return 0; } else if (err != -ENOSPC) { - drm_buddy_free_list(mm, blocks); + drm_buddy_free_list_internal(mm, blocks); return err; } /* Free blocks for the next iteration */ - drm_buddy_free_list(mm, blocks); + drm_buddy_free_list_internal(mm, blocks); } return -ENOSPC; @@ -700,6 +896,8 @@ int drm_buddy_block_trim(struct drm_buddy *mm, list_del(&block->link); mark_free(mm, block); mm->avail += drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail += drm_buddy_block_size(mm, block); /* Prevent recursively freeing this node */ parent = block->parent; @@ -711,6 +909,8 @@ int drm_buddy_block_trim(struct drm_buddy *mm, if (err) { mark_allocated(block); mm->avail -= drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); list_add(&block->link, blocks); } @@ -719,13 +919,28 @@ int drm_buddy_block_trim(struct drm_buddy *mm, } EXPORT_SYMBOL(drm_buddy_block_trim); +static struct drm_buddy_block * +__drm_buddy_alloc_blocks(struct drm_buddy *mm, + u64 start, u64 end, + unsigned int order, + unsigned long flags) +{ + if (flags & DRM_BUDDY_RANGE_ALLOCATION) + /* Allocate traversing within the range */ + return __drm_buddy_alloc_range_bias(mm, start, end, + order, flags); + else + /* Allocate from freelist */ + return alloc_from_freelist(mm, order, flags); +} + /** * drm_buddy_alloc_blocks - allocate power-of-two blocks * * @mm: DRM buddy manager to allocate from * @start: start of the allowed range for this block * @end: end of the allowed range for this block - * @size: size of the allocation + * @size: size of the allocation in bytes * @min_block_size: alignment of the allocation * @blocks: output list head to add allocated blocks * @flags: DRM_BUDDY_*_ALLOCATION flags @@ -800,23 +1015,33 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, BUG_ON(order < min_order); do { - if (flags & DRM_BUDDY_RANGE_ALLOCATION) - /* Allocate traversing within the range */ - block = alloc_range_bias(mm, start, end, order); - else - /* Allocate from freelist */ - block = alloc_from_freelist(mm, order, flags); - + block = __drm_buddy_alloc_blocks(mm, start, + end, + order, + flags); if (!IS_ERR(block)) break; if (order-- == min_order) { + /* Try allocation through force merge method */ + if (mm->clear_avail && + !__force_merge(mm, start, end, min_order)) { + block = __drm_buddy_alloc_blocks(mm, start, + end, + min_order, + flags); + if (!IS_ERR(block)) { + order = min_order; + break; + } + } + + /* + * Try contiguous block allocation through + * try harder method. + */ if (flags & DRM_BUDDY_CONTIGUOUS_ALLOCATION && !(flags & DRM_BUDDY_RANGE_ALLOCATION)) - /* - * Try contiguous block allocation through - * try harder method - */ return __alloc_contig_try_harder(mm, original_size, original_min_size, @@ -828,6 +1053,8 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, mark_allocated(block); mm->avail -= drm_buddy_block_size(mm, block); + if (drm_buddy_block_is_clear(block)) + mm->clear_avail -= drm_buddy_block_size(mm, block); kmemleak_update_trace(block); list_add_tail(&block->link, &allocated); @@ -866,7 +1093,7 @@ int drm_buddy_alloc_blocks(struct drm_buddy *mm, return 0; err_free: - drm_buddy_free_list(mm, &allocated); + drm_buddy_free_list_internal(mm, &allocated); return err; } EXPORT_SYMBOL(drm_buddy_alloc_blocks); @@ -899,8 +1126,8 @@ void drm_buddy_print(struct drm_buddy *mm, struct drm_printer *p) { int order; - drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB\n", - mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20); + drm_printf(p, "chunk_size: %lluKiB, total: %lluMiB, free: %lluMiB, clear_free: %lluMiB\n", + mm->chunk_size >> 10, mm->size >> 20, mm->avail >> 20, mm->clear_avail >> 20); for (order = mm->max_order; order >= 0; order--) { struct drm_buddy_block *block; diff --git a/drivers/gpu/drm/drm_displayid_internal.h b/drivers/gpu/drm/drm_displayid_internal.h index 56fd3bb0a779..aee1b86a73c1 100644 --- a/drivers/gpu/drm/drm_displayid_internal.h +++ b/drivers/gpu/drm/drm_displayid_internal.h @@ -31,7 +31,6 @@ struct drm_edid; #define VESA_IEEE_OUI 0x3a0292 /* DisplayID Structure versions */ -#define DISPLAY_ID_STRUCTURE_VER_12 0x12 #define DISPLAY_ID_STRUCTURE_VER_20 0x20 /* DisplayID Structure v1r2 Data Blocks */ diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 513590931cc5..4f54c91b31b2 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -7462,7 +7462,7 @@ static void drm_parse_tiled_block(struct drm_connector *connector, static bool displayid_is_tiled_block(const struct displayid_iter *iter, const struct displayid_block *block) { - return (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_12 && + return (displayid_version(iter) < DISPLAY_ID_STRUCTURE_VER_20 && block->tag == DATA_BLOCK_TILED_DISPLAY) || (displayid_version(iter) == DISPLAY_ID_STRUCTURE_VER_20 && block->tag == DATA_BLOCK_2_TILED_DISPLAY_TOPOLOGY); diff --git a/drivers/gpu/drm/drm_plane.c b/drivers/gpu/drm/drm_plane.c index eecc24c54efd..57662a1fd345 100644 --- a/drivers/gpu/drm/drm_plane.c +++ b/drivers/gpu/drm/drm_plane.c @@ -1750,7 +1750,7 @@ int drm_plane_create_scaling_filter_property(struct drm_plane *plane, EXPORT_SYMBOL(drm_plane_create_scaling_filter_property); /** - * drm_plane_add_size_hint_property - create a size hint property + * drm_plane_add_size_hints_property - create a size hints property * * @plane: drm plane * @hints: size hints diff --git a/drivers/gpu/drm/drm_print.c b/drivers/gpu/drm/drm_print.c index 699b7dbffd7b..cf2efb44722c 100644 --- a/drivers/gpu/drm/drm_print.c +++ b/drivers/gpu/drm/drm_print.c @@ -23,13 +23,13 @@ * Rob Clark */ -#include - +#include +#include #include #include #include #include -#include +#include #include #include diff --git a/drivers/gpu/drm/gud/gud_connector.c b/drivers/gpu/drm/gud/gud_connector.c index 034e78360d4f..0f07d77c5d52 100644 --- a/drivers/gpu/drm/gud/gud_connector.c +++ b/drivers/gpu/drm/gud/gud_connector.c @@ -221,7 +221,7 @@ static int gud_connector_get_modes(struct drm_connector *connector) struct gud_display_mode_req *reqmodes = NULL; struct gud_connector_get_edid_ctx edid_ctx; unsigned int i, num_modes = 0; - struct edid *edid = NULL; + const struct drm_edid *drm_edid = NULL; int idx, ret; if (!drm_dev_enter(connector->dev, &idx)) @@ -238,13 +238,13 @@ static int gud_connector_get_modes(struct drm_connector *connector) gud_conn_err(connector, "Invalid EDID size", ret); } else if (ret > 0) { edid_ctx.len = ret; - edid = drm_do_get_edid(connector, gud_connector_get_edid_block, &edid_ctx); + drm_edid = drm_edid_read_custom(connector, gud_connector_get_edid_block, &edid_ctx); } kfree(edid_ctx.buf); - drm_connector_update_edid_property(connector, edid); + drm_edid_connector_update(connector, drm_edid); - if (edid && edid_ctx.edid_override) + if (drm_edid && edid_ctx.edid_override) goto out; reqmodes = kmalloc_array(GUD_CONNECTOR_MAX_NUM_MODES, sizeof(*reqmodes), GFP_KERNEL); @@ -276,10 +276,10 @@ static int gud_connector_get_modes(struct drm_connector *connector) } out: if (!num_modes) - num_modes = drm_add_edid_modes(connector, edid); + num_modes = drm_edid_connector_add_modes(connector); kfree(reqmodes); - kfree(edid); + drm_edid_free(drm_edid); drm_dev_exit(idx); return num_modes; diff --git a/drivers/gpu/drm/i915/display/intel_dmc.c b/drivers/gpu/drm/i915/display/intel_dmc.c index 36c361cf72fc..cbd2ac5671b1 100644 --- a/drivers/gpu/drm/i915/display/intel_dmc.c +++ b/drivers/gpu/drm/i915/display/intel_dmc.c @@ -22,6 +22,7 @@ * */ +#include #include #include "i915_drv.h" diff --git a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c index 0d735d5c2b35..942345548bc3 100644 --- a/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c +++ b/drivers/gpu/drm/i915/i915_ttm_buddy_manager.c @@ -126,7 +126,7 @@ static int i915_ttm_buddy_man_alloc(struct ttm_resource_manager *man, return 0; err_free_blocks: - drm_buddy_free_list(mm, &bman_res->blocks); + drm_buddy_free_list(mm, &bman_res->blocks, 0); mutex_unlock(&bman->lock); err_free_res: ttm_resource_fini(man, &bman_res->base); @@ -141,7 +141,7 @@ static void i915_ttm_buddy_man_free(struct ttm_resource_manager *man, struct i915_ttm_buddy_manager *bman = to_buddy_manager(man); mutex_lock(&bman->lock); - drm_buddy_free_list(&bman->mm, &bman_res->blocks); + drm_buddy_free_list(&bman->mm, &bman_res->blocks, 0); bman->visible_avail += bman_res->used_visible_size; mutex_unlock(&bman->lock); @@ -345,7 +345,7 @@ int i915_ttm_buddy_man_fini(struct ttm_device *bdev, unsigned int type) ttm_set_driver_manager(bdev, type, NULL); mutex_lock(&bman->lock); - drm_buddy_free_list(mm, &bman->reserved); + drm_buddy_free_list(mm, &bman->reserved, 0); drm_buddy_fini(mm); bman->visible_avail += bman->visible_reserved; WARN_ON_ONCE(bman->visible_avail != bman->visible_size); diff --git a/drivers/gpu/drm/imagination/pvr_fw_trace.c b/drivers/gpu/drm/imagination/pvr_fw_trace.c index 31199e45b72e..73707daa4e52 100644 --- a/drivers/gpu/drm/imagination/pvr_fw_trace.c +++ b/drivers/gpu/drm/imagination/pvr_fw_trace.c @@ -12,6 +12,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c index a6bc1bdb3d0d..a10cff3ca1fe 100644 --- a/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c +++ b/drivers/gpu/drm/meson/meson_dw_mipi_dsi.c @@ -95,6 +95,7 @@ static int dw_mipi_dsi_phy_init(void *priv_data) return ret; } + clk_disable_unprepare(mipi_dsi->px_clk); ret = clk_set_rate(mipi_dsi->px_clk, mipi_dsi->mode->clock * 1000); if (ret) { @@ -103,6 +104,12 @@ static int dw_mipi_dsi_phy_init(void *priv_data) return ret; } + ret = clk_prepare_enable(mipi_dsi->px_clk); + if (ret) { + dev_err(mipi_dsi->dev, "Failed to enable DSI Pixel clock (ret %d)\n", ret); + return ret; + } + switch (mipi_dsi->dsi_device->format) { case MIPI_DSI_FMT_RGB888: dpi_data_format = DPI_COLOR_24BIT; diff --git a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c index 0bf8a83e8df3..8586f2761782 100644 --- a/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c +++ b/drivers/gpu/drm/msm/disp/dpu1/dpu_hw_sspp.c @@ -2,6 +2,8 @@ /* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved. */ +#include + #include "dpu_hwio.h" #include "dpu_hw_catalog.h" #include "dpu_hw_lm.h" diff --git a/drivers/gpu/drm/nouveau/dispnv50/crc.c b/drivers/gpu/drm/nouveau/dispnv50/crc.c index 9c942fbd836d..5936b6b3b15d 100644 --- a/drivers/gpu/drm/nouveau/dispnv50/crc.c +++ b/drivers/gpu/drm/nouveau/dispnv50/crc.c @@ -1,5 +1,7 @@ // SPDX-License-Identifier: MIT +#include #include + #include #include #include diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig index ab67789e59a2..e54f6f5604ed 100644 --- a/drivers/gpu/drm/panel/Kconfig +++ b/drivers/gpu/drm/panel/Kconfig @@ -553,6 +553,18 @@ config DRM_PANEL_RAYDIUM_RM692E5 Say Y here if you want to enable support for Raydium RM692E5-based display panels, such as the one found in the Fairphone 5 smartphone. +config DRM_PANEL_RAYDIUM_RM69380 + tristate "Raydium RM69380-based DSI panel" + depends on OF && GPIOLIB + depends on DRM_MIPI_DSI + depends on BACKLIGHT_CLASS_DEVICE + help + Say Y here if you want to enable support for Raydium RM69380-based + display panels. + + This panel controller can be found in the Lenovo Xiaoxin Pad Pro 2021 + in combination with an EDO OLED panel. + config DRM_PANEL_RONBO_RB070D30 tristate "Ronbo Electronics RB070D30 panel" depends on OF diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile index 0b40b010e8e7..f0203f6e02f4 100644 --- a/drivers/gpu/drm/panel/Makefile +++ b/drivers/gpu/drm/panel/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN) += panel-raspberrypi-touchscreen obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM67191) += panel-raydium-rm67191.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM68200) += panel-raydium-rm68200.o obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM692E5) += panel-raydium-rm692e5.o +obj-$(CONFIG_DRM_PANEL_RAYDIUM_RM69380) += panel-raydium-rm69380.o obj-$(CONFIG_DRM_PANEL_RONBO_RB070D30) += panel-ronbo-rb070d30.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_ATNA33XC20) += panel-samsung-atna33xc20.o obj-$(CONFIG_DRM_PANEL_SAMSUNG_DB7430) += panel-samsung-db7430.o diff --git a/drivers/gpu/drm/panel/panel-edp.c b/drivers/gpu/drm/panel/panel-edp.c index d29bacf25c12..6db277efcbb7 100644 --- a/drivers/gpu/drm/panel/panel-edp.c +++ b/drivers/gpu/drm/panel/panel-edp.c @@ -242,7 +242,7 @@ struct panel_edp { const struct edp_panel_entry *detected_panel; - struct edid *edid; + const struct drm_edid *drm_edid; struct drm_display_mode override_mode; @@ -617,13 +617,16 @@ static int panel_edp_get_modes(struct drm_panel *panel, if (p->ddc) { pm_runtime_get_sync(panel->dev); - if (!p->edid) - p->edid = drm_get_edid(connector, p->ddc); + if (!p->drm_edid) + p->drm_edid = drm_edid_read_ddc(connector, p->ddc); + + drm_edid_connector_update(connector, p->drm_edid); + /* * If both edid and hard-coded modes exists, skip edid modes to * avoid multiple preferred modes. */ - if (p->edid && !has_hard_coded_modes) { + if (p->drm_edid && !has_hard_coded_modes) { if (has_override_edid_mode) { /* * override_edid_mode is specified. Use @@ -632,7 +635,7 @@ static int panel_edp_get_modes(struct drm_panel *panel, num += panel_edp_override_edid_mode(p, connector, p->detected_panel->override_edid_mode); } else { - num += drm_add_edid_modes(connector, p->edid); + num += drm_edid_connector_add_modes(connector); } } @@ -981,8 +984,8 @@ static void panel_edp_remove(struct device *dev) if (panel->ddc && (!panel->aux || panel->ddc != &panel->aux->ddc)) put_device(&panel->ddc->dev); - kfree(panel->edid); - panel->edid = NULL; + drm_edid_free(panel->drm_edid); + panel->drm_edid = NULL; } static void panel_edp_shutdown(struct device *dev) @@ -2075,6 +2078,8 @@ static const struct edp_panel_entry edp_panels[] = { EDP_PANEL_ENTRY('C', 'S', 'O', 0x1200, &delay_200_500_e50_p2e200, "MNC207QS1-1"), + EDP_PANEL_ENTRY('C', 'S', 'W', 0x1100, &delay_200_500_e80_d50, "MNB601LS1-1"), + EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d51, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5b, &delay_200_500_e200, "Unknown"), EDP_PANEL_ENTRY('H', 'K', 'C', 0x2d5c, &delay_200_500_e200, "MB116AN01-2"), diff --git a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c index 3e0a8e0d58a0..483dc88d16d8 100644 --- a/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c +++ b/drivers/gpu/drm/panel/panel-jdi-fhd-r63452.c @@ -247,6 +247,7 @@ static int jdi_fhd_r63452_probe(struct mipi_dsi_device *dsi) drm_panel_init(&ctx->panel, dev, &jdi_fhd_r63452_panel_funcs, DRM_MODE_CONNECTOR_DSI); + ctx->panel.prepare_prev_first = true; ret = drm_panel_of_backlight(&ctx->panel); if (ret) diff --git a/drivers/gpu/drm/panel/panel-khadas-ts050.c b/drivers/gpu/drm/panel/panel-khadas-ts050.c index b942a0162274..c54be0cc3f08 100644 --- a/drivers/gpu/drm/panel/panel-khadas-ts050.c +++ b/drivers/gpu/drm/panel/panel-khadas-ts050.c @@ -25,6 +25,7 @@ struct khadas_ts050_panel { struct regulator *supply; struct gpio_desc *reset_gpio; struct gpio_desc *enable_gpio; + struct khadas_ts050_panel_data *panel_data; bool prepared; bool enabled; @@ -32,544 +33,601 @@ struct khadas_ts050_panel { struct khadas_ts050_panel_cmd { u8 cmd; - u8 data; + u8 data[55]; + u8 size; +}; + +struct khadas_ts050_panel_data { + struct khadas_ts050_panel_cmd *init_code; + int len; +}; + +static const struct khadas_ts050_panel_cmd ts050v2_init_code[] = { + {0xB9, {0xFF, 0x83, 0x99}, 0x03}, + {0xBA, {0x63, 0x23, 0x68, 0xCF}, 0x04}, + {0xD2, {0x55}, 0x01}, + {0xB1, {0x02, 0x04, 0x70, 0x90, 0x01, 0x32, 0x33, + 0x11, 0x11, 0x4D, 0x57, 0x56, 0x73, 0x02, 0x02}, 0x0f}, + {0xB2, {0x00, 0x80, 0x80, 0xAE, 0x0A, 0x0E, 0x75, 0x11, 0x00, 0x00, 0x00}, 0x0b}, + {0xB4, {0x00, 0xFF, 0x04, 0xA4, 0x02, 0xA0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, + 0x00, 0x24, 0x02, 0x04, 0x0A, 0x21, 0x03, 0x00, 0x00, 0x08, 0xA6, 0x88, + 0x04, 0xA4, 0x02, 0xA0, 0x00, 0x00, 0x10, 0x00, 0x00, 0x02, 0x00, 0x24, + 0x02, 0x04, 0x0A, 0x00, 0x00, 0x08, 0xA6, 0x00, 0x08, 0x11}, 0x2e}, + {0xD3, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, + 0x18, 0x32, 0x10, 0x09, 0x00, 0x09, 0x32, + 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x00, 0x02, 0x02, 0x03, 0x00, 0x00, 0x00, 0x0A, + 0x40}, 0x21}, + {0xD5, {0x18, 0x18, 0x18, 0x18, 0x21, 0x20, 0x18, 0x18, 0x19, 0x19, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x03, 0x02, 0x01, 0x00, 0x2F, 0x2F, + 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, 0x20}, + {0xD6, {0x18, 0x18, 0x18, 0x18, 0x20, 0x21, 0x19, 0x19, 0x18, 0x18, 0x19, + 0x19, 0x18, 0x18, 0x18, 0x18, 0x00, 0x01, 0x02, 0x03, 0x2F, 0x2F, + 0x30, 0x30, 0x31, 0x31, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18}, 0x20}, + {0xD8, {0x0A, 0xBE, 0xFA, 0xA0, 0x0A, 0xBE, 0xFA, 0xA0}, 0x08}, + {0xBD, {0x01}, 0x01}, + {0xD8, {0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0}, 0x08}, + {0xBD, {0x02}, 0x01}, + {0xD8, {0x0F, 0xFF, 0xFF, 0xE0, 0x0F, 0xFF, 0xFF, 0xE0}, 0x08}, + {0xBD, {0x00}, 0x01}, + {0xE0, {0x01, 0x35, 0x41, 0x3B, 0x79, 0x81, 0x8C, 0x85, 0x8E, + 0x95, 0x9B, 0xA0, 0xA4, 0xAB, 0xB1, 0xB3, 0xB7, 0xC5, 0xBD, 0xC5, + 0xB6, 0xC2, 0xC2, 0x62, 0x5D, 0x66, 0x73, 0x01, 0x35, 0x41, 0x3B, + 0x79, 0x81, 0x8C, 0x85, 0x8E, 0x95, 0x9B, 0xA0, 0xA4, 0xAB, 0xB1, + 0xB3, 0xB7, 0xB5, 0xBD, 0xC5, 0xB6, 0xC2, 0xC2, 0x62, 0x5D, 0x66, + 0x73}, 0x36}, + {0xB6, {0x97, 0x97}, 0x02}, + {0xCC, {0xC8}, 0x02}, + {0xBF, {0x40, 0x41, 0x50, 0x19}, 0x04}, + {0xC6, {0xFF, 0xF9}, 0x02}, + {0xC0, {0x25, 0x5A}, 0x02}, }; /* Only the CMD1 User Command set is documented */ -static const struct khadas_ts050_panel_cmd init_code[] = { +static const struct khadas_ts050_panel_cmd ts050_init_code[] = { /* Select Unknown CMD Page (Undocumented) */ - {0xff, 0xee}, + {0xff, {0xee}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x1f, 0x45}, - {0x24, 0x4f}, - {0x38, 0xc8}, - {0x39, 0x27}, - {0x1e, 0x77}, - {0x1d, 0x0f}, - {0x7e, 0x71}, - {0x7c, 0x03}, - {0xff, 0x00}, - {0xfb, 0x01}, - {0x35, 0x01}, + {0xfb, {0x01}, 0x01}, + {0x1f, {0x45}, 0x01}, + {0x24, {0x4f}, 0x01}, + {0x38, {0xc8}, 0x01}, + {0x39, {0x27}, 0x01}, + {0x1e, {0x77}, 0x01}, + {0x1d, {0x0f}, 0x01}, + {0x7e, {0x71}, 0x01}, + {0x7c, {0x03}, 0x01}, + {0xff, {0x00}, 0x01}, + {0xfb, {0x01}, 0x01}, + {0x35, {0x01}, 0x01}, /* Select CMD2 Page0 (Undocumented) */ - {0xff, 0x01}, + {0xff, {0x01}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x00, 0x01}, - {0x01, 0x55}, - {0x02, 0x40}, - {0x05, 0x40}, - {0x06, 0x4a}, - {0x07, 0x24}, - {0x08, 0x0c}, - {0x0b, 0x7d}, - {0x0c, 0x7d}, - {0x0e, 0xb0}, - {0x0f, 0xae}, - {0x11, 0x10}, - {0x12, 0x10}, - {0x13, 0x03}, - {0x14, 0x4a}, - {0x15, 0x12}, - {0x16, 0x12}, - {0x18, 0x00}, - {0x19, 0x77}, - {0x1a, 0x55}, - {0x1b, 0x13}, - {0x1c, 0x00}, - {0x1d, 0x00}, - {0x1e, 0x13}, - {0x1f, 0x00}, - {0x23, 0x00}, - {0x24, 0x00}, - {0x25, 0x00}, - {0x26, 0x00}, - {0x27, 0x00}, - {0x28, 0x00}, - {0x35, 0x00}, - {0x66, 0x00}, - {0x58, 0x82}, - {0x59, 0x02}, - {0x5a, 0x02}, - {0x5b, 0x02}, - {0x5c, 0x82}, - {0x5d, 0x82}, - {0x5e, 0x02}, - {0x5f, 0x02}, - {0x72, 0x31}, + {0xfb, {0x01}, 0x01}, + {0x00, {0x01}, 0x01}, + {0x01, {0x55}, 0x01}, + {0x02, {0x40}, 0x01}, + {0x05, {0x40}, 0x01}, + {0x06, {0x4a}, 0x01}, + {0x07, {0x24}, 0x01}, + {0x08, {0x0c}, 0x01}, + {0x0b, {0x7d}, 0x01}, + {0x0c, {0x7d}, 0x01}, + {0x0e, {0xb0}, 0x01}, + {0x0f, {0xae}, 0x01}, + {0x11, {0x10}, 0x01}, + {0x12, {0x10}, 0x01}, + {0x13, {0x03}, 0x01}, + {0x14, {0x4a}, 0x01}, + {0x15, {0x12}, 0x01}, + {0x16, {0x12}, 0x01}, + {0x18, {0x00}, 0x01}, + {0x19, {0x77}, 0x01}, + {0x1a, {0x55}, 0x01}, + {0x1b, {0x13}, 0x01}, + {0x1c, {0x00}, 0x01}, + {0x1d, {0x00}, 0x01}, + {0x1e, {0x13}, 0x01}, + {0x1f, {0x00}, 0x01}, + {0x23, {0x00}, 0x01}, + {0x24, {0x00}, 0x01}, + {0x25, {0x00}, 0x01}, + {0x26, {0x00}, 0x01}, + {0x27, {0x00}, 0x01}, + {0x28, {0x00}, 0x01}, + {0x35, {0x00}, 0x01}, + {0x66, {0x00}, 0x01}, + {0x58, {0x82}, 0x01}, + {0x59, {0x02}, 0x01}, + {0x5a, {0x02}, 0x01}, + {0x5b, {0x02}, 0x01}, + {0x5c, {0x82}, 0x01}, + {0x5d, {0x82}, 0x01}, + {0x5e, {0x02}, 0x01}, + {0x5f, {0x02}, 0x01}, + {0x72, {0x31}, 0x01}, /* Select CMD2 Page4 (Undocumented) */ - {0xff, 0x05}, + {0xff, {0x05}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x00, 0x01}, - {0x01, 0x0b}, - {0x02, 0x0c}, - {0x03, 0x09}, - {0x04, 0x0a}, - {0x05, 0x00}, - {0x06, 0x0f}, - {0x07, 0x10}, - {0x08, 0x00}, - {0x09, 0x00}, - {0x0a, 0x00}, - {0x0b, 0x00}, - {0x0c, 0x00}, - {0x0d, 0x13}, - {0x0e, 0x15}, - {0x0f, 0x17}, - {0x10, 0x01}, - {0x11, 0x0b}, - {0x12, 0x0c}, - {0x13, 0x09}, - {0x14, 0x0a}, - {0x15, 0x00}, - {0x16, 0x0f}, - {0x17, 0x10}, - {0x18, 0x00}, - {0x19, 0x00}, - {0x1a, 0x00}, - {0x1b, 0x00}, - {0x1c, 0x00}, - {0x1d, 0x13}, - {0x1e, 0x15}, - {0x1f, 0x17}, - {0x20, 0x00}, - {0x21, 0x03}, - {0x22, 0x01}, - {0x23, 0x40}, - {0x24, 0x40}, - {0x25, 0xed}, - {0x29, 0x58}, - {0x2a, 0x12}, - {0x2b, 0x01}, - {0x4b, 0x06}, - {0x4c, 0x11}, - {0x4d, 0x20}, - {0x4e, 0x02}, - {0x4f, 0x02}, - {0x50, 0x20}, - {0x51, 0x61}, - {0x52, 0x01}, - {0x53, 0x63}, - {0x54, 0x77}, - {0x55, 0xed}, - {0x5b, 0x00}, - {0x5c, 0x00}, - {0x5d, 0x00}, - {0x5e, 0x00}, - {0x5f, 0x15}, - {0x60, 0x75}, - {0x61, 0x00}, - {0x62, 0x00}, - {0x63, 0x00}, - {0x64, 0x00}, - {0x65, 0x00}, - {0x66, 0x00}, - {0x67, 0x00}, - {0x68, 0x04}, - {0x69, 0x00}, - {0x6a, 0x00}, - {0x6c, 0x40}, - {0x75, 0x01}, - {0x76, 0x01}, - {0x7a, 0x80}, - {0x7b, 0xa3}, - {0x7c, 0xd8}, - {0x7d, 0x60}, - {0x7f, 0x15}, - {0x80, 0x81}, - {0x83, 0x05}, - {0x93, 0x08}, - {0x94, 0x10}, - {0x8a, 0x00}, - {0x9b, 0x0f}, - {0xea, 0xff}, - {0xec, 0x00}, + {0xfb, {0x01}, 0x01}, + {0x00, {0x01}, 0x01}, + {0x01, {0x0b}, 0x01}, + {0x02, {0x0c}, 0x01}, + {0x03, {0x09}, 0x01}, + {0x04, {0x0a}, 0x01}, + {0x05, {0x00}, 0x01}, + {0x06, {0x0f}, 0x01}, + {0x07, {0x10}, 0x01}, + {0x08, {0x00}, 0x01}, + {0x09, {0x00}, 0x01}, + {0x0a, {0x00}, 0x01}, + {0x0b, {0x00}, 0x01}, + {0x0c, {0x00}, 0x01}, + {0x0d, {0x13}, 0x01}, + {0x0e, {0x15}, 0x01}, + {0x0f, {0x17}, 0x01}, + {0x10, {0x01}, 0x01}, + {0x11, {0x0b}, 0x01}, + {0x12, {0x0c}, 0x01}, + {0x13, {0x09}, 0x01}, + {0x14, {0x0a}, 0x01}, + {0x15, {0x00}, 0x01}, + {0x16, {0x0f}, 0x01}, + {0x17, {0x10}, 0x01}, + {0x18, {0x00}, 0x01}, + {0x19, {0x00}, 0x01}, + {0x1a, {0x00}, 0x01}, + {0x1b, {0x00}, 0x01}, + {0x1c, {0x00}, 0x01}, + {0x1d, {0x13}, 0x01}, + {0x1e, {0x15}, 0x01}, + {0x1f, {0x17}, 0x01}, + {0x20, {0x00}, 0x01}, + {0x21, {0x03}, 0x01}, + {0x22, {0x01}, 0x01}, + {0x23, {0x40}, 0x01}, + {0x24, {0x40}, 0x01}, + {0x25, {0xed}, 0x01}, + {0x29, {0x58}, 0x01}, + {0x2a, {0x12}, 0x01}, + {0x2b, {0x01}, 0x01}, + {0x4b, {0x06}, 0x01}, + {0x4c, {0x11}, 0x01}, + {0x4d, {0x20}, 0x01}, + {0x4e, {0x02}, 0x01}, + {0x4f, {0x02}, 0x01}, + {0x50, {0x20}, 0x01}, + {0x51, {0x61}, 0x01}, + {0x52, {0x01}, 0x01}, + {0x53, {0x63}, 0x01}, + {0x54, {0x77}, 0x01}, + {0x55, {0xed}, 0x01}, + {0x5b, {0x00}, 0x01}, + {0x5c, {0x00}, 0x01}, + {0x5d, {0x00}, 0x01}, + {0x5e, {0x00}, 0x01}, + {0x5f, {0x15}, 0x01}, + {0x60, {0x75}, 0x01}, + {0x61, {0x00}, 0x01}, + {0x62, {0x00}, 0x01}, + {0x63, {0x00}, 0x01}, + {0x64, {0x00}, 0x01}, + {0x65, {0x00}, 0x01}, + {0x66, {0x00}, 0x01}, + {0x67, {0x00}, 0x01}, + {0x68, {0x04}, 0x01}, + {0x69, {0x00}, 0x01}, + {0x6a, {0x00}, 0x01}, + {0x6c, {0x40}, 0x01}, + {0x75, {0x01}, 0x01}, + {0x76, {0x01}, 0x01}, + {0x7a, {0x80}, 0x01}, + {0x7b, {0xa3}, 0x01}, + {0x7c, {0xd8}, 0x01}, + {0x7d, {0x60}, 0x01}, + {0x7f, {0x15}, 0x01}, + {0x80, {0x81}, 0x01}, + {0x83, {0x05}, 0x01}, + {0x93, {0x08}, 0x01}, + {0x94, {0x10}, 0x01}, + {0x8a, {0x00}, 0x01}, + {0x9b, {0x0f}, 0x01}, + {0xea, {0xff}, 0x01}, + {0xec, {0x00}, 0x01}, /* Select CMD2 Page0 (Undocumented) */ - {0xff, 0x01}, + {0xff, {0x01}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x75, 0x00}, - {0x76, 0xdf}, - {0x77, 0x00}, - {0x78, 0xe4}, - {0x79, 0x00}, - {0x7a, 0xed}, - {0x7b, 0x00}, - {0x7c, 0xf6}, - {0x7d, 0x00}, - {0x7e, 0xff}, - {0x7f, 0x01}, - {0x80, 0x07}, - {0x81, 0x01}, - {0x82, 0x10}, - {0x83, 0x01}, - {0x84, 0x18}, - {0x85, 0x01}, - {0x86, 0x20}, - {0x87, 0x01}, - {0x88, 0x3d}, - {0x89, 0x01}, - {0x8a, 0x56}, - {0x8b, 0x01}, - {0x8c, 0x84}, - {0x8d, 0x01}, - {0x8e, 0xab}, - {0x8f, 0x01}, - {0x90, 0xec}, - {0x91, 0x02}, - {0x92, 0x22}, - {0x93, 0x02}, - {0x94, 0x23}, - {0x95, 0x02}, - {0x96, 0x55}, - {0x97, 0x02}, - {0x98, 0x8b}, - {0x99, 0x02}, - {0x9a, 0xaf}, - {0x9b, 0x02}, - {0x9c, 0xdf}, - {0x9d, 0x03}, - {0x9e, 0x01}, - {0x9f, 0x03}, - {0xa0, 0x2c}, - {0xa2, 0x03}, - {0xa3, 0x39}, - {0xa4, 0x03}, - {0xa5, 0x47}, - {0xa6, 0x03}, - {0xa7, 0x56}, - {0xa9, 0x03}, - {0xaa, 0x66}, - {0xab, 0x03}, - {0xac, 0x76}, - {0xad, 0x03}, - {0xae, 0x85}, - {0xaf, 0x03}, - {0xb0, 0x90}, - {0xb1, 0x03}, - {0xb2, 0xcb}, - {0xb3, 0x00}, - {0xb4, 0xdf}, - {0xb5, 0x00}, - {0xb6, 0xe4}, - {0xb7, 0x00}, - {0xb8, 0xed}, - {0xb9, 0x00}, - {0xba, 0xf6}, - {0xbb, 0x00}, - {0xbc, 0xff}, - {0xbd, 0x01}, - {0xbe, 0x07}, - {0xbf, 0x01}, - {0xc0, 0x10}, - {0xc1, 0x01}, - {0xc2, 0x18}, - {0xc3, 0x01}, - {0xc4, 0x20}, - {0xc5, 0x01}, - {0xc6, 0x3d}, - {0xc7, 0x01}, - {0xc8, 0x56}, - {0xc9, 0x01}, - {0xca, 0x84}, - {0xcb, 0x01}, - {0xcc, 0xab}, - {0xcd, 0x01}, - {0xce, 0xec}, - {0xcf, 0x02}, - {0xd0, 0x22}, - {0xd1, 0x02}, - {0xd2, 0x23}, - {0xd3, 0x02}, - {0xd4, 0x55}, - {0xd5, 0x02}, - {0xd6, 0x8b}, - {0xd7, 0x02}, - {0xd8, 0xaf}, - {0xd9, 0x02}, - {0xda, 0xdf}, - {0xdb, 0x03}, - {0xdc, 0x01}, - {0xdd, 0x03}, - {0xde, 0x2c}, - {0xdf, 0x03}, - {0xe0, 0x39}, - {0xe1, 0x03}, - {0xe2, 0x47}, - {0xe3, 0x03}, - {0xe4, 0x56}, - {0xe5, 0x03}, - {0xe6, 0x66}, - {0xe7, 0x03}, - {0xe8, 0x76}, - {0xe9, 0x03}, - {0xea, 0x85}, - {0xeb, 0x03}, - {0xec, 0x90}, - {0xed, 0x03}, - {0xee, 0xcb}, - {0xef, 0x00}, - {0xf0, 0xbb}, - {0xf1, 0x00}, - {0xf2, 0xc0}, - {0xf3, 0x00}, - {0xf4, 0xcc}, - {0xf5, 0x00}, - {0xf6, 0xd6}, - {0xf7, 0x00}, - {0xf8, 0xe1}, - {0xf9, 0x00}, - {0xfa, 0xea}, + {0xfb, {0x01}, 0x01}, + {0x75, {0x00}, 0x01}, + {0x76, {0xdf}, 0x01}, + {0x77, {0x00}, 0x01}, + {0x78, {0xe4}, 0x01}, + {0x79, {0x00}, 0x01}, + {0x7a, {0xed}, 0x01}, + {0x7b, {0x00}, 0x01}, + {0x7c, {0xf6}, 0x01}, + {0x7d, {0x00}, 0x01}, + {0x7e, {0xff}, 0x01}, + {0x7f, {0x01}, 0x01}, + {0x80, {0x07}, 0x01}, + {0x81, {0x01}, 0x01}, + {0x82, {0x10}, 0x01}, + {0x83, {0x01}, 0x01}, + {0x84, {0x18}, 0x01}, + {0x85, {0x01}, 0x01}, + {0x86, {0x20}, 0x01}, + {0x87, {0x01}, 0x01}, + {0x88, {0x3d}, 0x01}, + {0x89, {0x01}, 0x01}, + {0x8a, {0x56}, 0x01}, + {0x8b, {0x01}, 0x01}, + {0x8c, {0x84}, 0x01}, + {0x8d, {0x01}, 0x01}, + {0x8e, {0xab}, 0x01}, + {0x8f, {0x01}, 0x01}, + {0x90, {0xec}, 0x01}, + {0x91, {0x02}, 0x01}, + {0x92, {0x22}, 0x01}, + {0x93, {0x02}, 0x01}, + {0x94, {0x23}, 0x01}, + {0x95, {0x02}, 0x01}, + {0x96, {0x55}, 0x01}, + {0x97, {0x02}, 0x01}, + {0x98, {0x8b}, 0x01}, + {0x99, {0x02}, 0x01}, + {0x9a, {0xaf}, 0x01}, + {0x9b, {0x02}, 0x01}, + {0x9c, {0xdf}, 0x01}, + {0x9d, {0x03}, 0x01}, + {0x9e, {0x01}, 0x01}, + {0x9f, {0x03}, 0x01}, + {0xa0, {0x2c}, 0x01}, + {0xa2, {0x03}, 0x01}, + {0xa3, {0x39}, 0x01}, + {0xa4, {0x03}, 0x01}, + {0xa5, {0x47}, 0x01}, + {0xa6, {0x03}, 0x01}, + {0xa7, {0x56}, 0x01}, + {0xa9, {0x03}, 0x01}, + {0xaa, {0x66}, 0x01}, + {0xab, {0x03}, 0x01}, + {0xac, {0x76}, 0x01}, + {0xad, {0x03}, 0x01}, + {0xae, {0x85}, 0x01}, + {0xaf, {0x03}, 0x01}, + {0xb0, {0x90}, 0x01}, + {0xb1, {0x03}, 0x01}, + {0xb2, {0xcb}, 0x01}, + {0xb3, {0x00}, 0x01}, + {0xb4, {0xdf}, 0x01}, + {0xb5, {0x00}, 0x01}, + {0xb6, {0xe4}, 0x01}, + {0xb7, {0x00}, 0x01}, + {0xb8, {0xed}, 0x01}, + {0xb9, {0x00}, 0x01}, + {0xba, {0xf6}, 0x01}, + {0xbb, {0x00}, 0x01}, + {0xbc, {0xff}, 0x01}, + {0xbd, {0x01}, 0x01}, + {0xbe, {0x07}, 0x01}, + {0xbf, {0x01}, 0x01}, + {0xc0, {0x10}, 0x01}, + {0xc1, {0x01}, 0x01}, + {0xc2, {0x18}, 0x01}, + {0xc3, {0x01}, 0x01}, + {0xc4, {0x20}, 0x01}, + {0xc5, {0x01}, 0x01}, + {0xc6, {0x3d}, 0x01}, + {0xc7, {0x01}, 0x01}, + {0xc8, {0x56}, 0x01}, + {0xc9, {0x01}, 0x01}, + {0xca, {0x84}, 0x01}, + {0xcb, {0x01}, 0x01}, + {0xcc, {0xab}, 0x01}, + {0xcd, {0x01}, 0x01}, + {0xce, {0xec}, 0x01}, + {0xcf, {0x02}, 0x01}, + {0xd0, {0x22}, 0x01}, + {0xd1, {0x02}, 0x01}, + {0xd2, {0x23}, 0x01}, + {0xd3, {0x02}, 0x01}, + {0xd4, {0x55}, 0x01}, + {0xd5, {0x02}, 0x01}, + {0xd6, {0x8b}, 0x01}, + {0xd7, {0x02}, 0x01}, + {0xd8, {0xaf}, 0x01}, + {0xd9, {0x02}, 0x01}, + {0xda, {0xdf}, 0x01}, + {0xdb, {0x03}, 0x01}, + {0xdc, {0x01}, 0x01}, + {0xdd, {0x03}, 0x01}, + {0xde, {0x2c}, 0x01}, + {0xdf, {0x03}, 0x01}, + {0xe0, {0x39}, 0x01}, + {0xe1, {0x03}, 0x01}, + {0xe2, {0x47}, 0x01}, + {0xe3, {0x03}, 0x01}, + {0xe4, {0x56}, 0x01}, + {0xe5, {0x03}, 0x01}, + {0xe6, {0x66}, 0x01}, + {0xe7, {0x03}, 0x01}, + {0xe8, {0x76}, 0x01}, + {0xe9, {0x03}, 0x01}, + {0xea, {0x85}, 0x01}, + {0xeb, {0x03}, 0x01}, + {0xec, {0x90}, 0x01}, + {0xed, {0x03}, 0x01}, + {0xee, {0xcb}, 0x01}, + {0xef, {0x00}, 0x01}, + {0xf0, {0xbb}, 0x01}, + {0xf1, {0x00}, 0x01}, + {0xf2, {0xc0}, 0x01}, + {0xf3, {0x00}, 0x01}, + {0xf4, {0xcc}, 0x01}, + {0xf5, {0x00}, 0x01}, + {0xf6, {0xd6}, 0x01}, + {0xf7, {0x00}, 0x01}, + {0xf8, {0xe1}, 0x01}, + {0xf9, {0x00}, 0x01}, + {0xfa, {0xea}, 0x01}, /* Select CMD2 Page2 (Undocumented) */ - {0xff, 0x02}, + {0xff, {0x02}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, - {0x00, 0x00}, - {0x01, 0xf4}, - {0x02, 0x00}, - {0x03, 0xef}, - {0x04, 0x01}, - {0x05, 0x07}, - {0x06, 0x01}, - {0x07, 0x28}, - {0x08, 0x01}, - {0x09, 0x44}, - {0x0a, 0x01}, - {0x0b, 0x76}, - {0x0c, 0x01}, - {0x0d, 0xa0}, - {0x0e, 0x01}, - {0x0f, 0xe7}, - {0x10, 0x02}, - {0x11, 0x1f}, - {0x12, 0x02}, - {0x13, 0x22}, - {0x14, 0x02}, - {0x15, 0x54}, - {0x16, 0x02}, - {0x17, 0x8b}, - {0x18, 0x02}, - {0x19, 0xaf}, - {0x1a, 0x02}, - {0x1b, 0xe0}, - {0x1c, 0x03}, - {0x1d, 0x01}, - {0x1e, 0x03}, - {0x1f, 0x2d}, - {0x20, 0x03}, - {0x21, 0x39}, - {0x22, 0x03}, - {0x23, 0x47}, - {0x24, 0x03}, - {0x25, 0x57}, - {0x26, 0x03}, - {0x27, 0x65}, - {0x28, 0x03}, - {0x29, 0x77}, - {0x2a, 0x03}, - {0x2b, 0x85}, - {0x2d, 0x03}, - {0x2f, 0x8f}, - {0x30, 0x03}, - {0x31, 0xcb}, - {0x32, 0x00}, - {0x33, 0xbb}, - {0x34, 0x00}, - {0x35, 0xc0}, - {0x36, 0x00}, - {0x37, 0xcc}, - {0x38, 0x00}, - {0x39, 0xd6}, - {0x3a, 0x00}, - {0x3b, 0xe1}, - {0x3d, 0x00}, - {0x3f, 0xea}, - {0x40, 0x00}, - {0x41, 0xf4}, - {0x42, 0x00}, - {0x43, 0xfe}, - {0x44, 0x01}, - {0x45, 0x07}, - {0x46, 0x01}, - {0x47, 0x28}, - {0x48, 0x01}, - {0x49, 0x44}, - {0x4a, 0x01}, - {0x4b, 0x76}, - {0x4c, 0x01}, - {0x4d, 0xa0}, - {0x4e, 0x01}, - {0x4f, 0xe7}, - {0x50, 0x02}, - {0x51, 0x1f}, - {0x52, 0x02}, - {0x53, 0x22}, - {0x54, 0x02}, - {0x55, 0x54}, - {0x56, 0x02}, - {0x58, 0x8b}, - {0x59, 0x02}, - {0x5a, 0xaf}, - {0x5b, 0x02}, - {0x5c, 0xe0}, - {0x5d, 0x03}, - {0x5e, 0x01}, - {0x5f, 0x03}, - {0x60, 0x2d}, - {0x61, 0x03}, - {0x62, 0x39}, - {0x63, 0x03}, - {0x64, 0x47}, - {0x65, 0x03}, - {0x66, 0x57}, - {0x67, 0x03}, - {0x68, 0x65}, - {0x69, 0x03}, - {0x6a, 0x77}, - {0x6b, 0x03}, - {0x6c, 0x85}, - {0x6d, 0x03}, - {0x6e, 0x8f}, - {0x6f, 0x03}, - {0x70, 0xcb}, - {0x71, 0x00}, - {0x72, 0x00}, - {0x73, 0x00}, - {0x74, 0x21}, - {0x75, 0x00}, - {0x76, 0x4c}, - {0x77, 0x00}, - {0x78, 0x6b}, - {0x79, 0x00}, - {0x7a, 0x85}, - {0x7b, 0x00}, - {0x7c, 0x9a}, - {0x7d, 0x00}, - {0x7e, 0xad}, - {0x7f, 0x00}, - {0x80, 0xbe}, - {0x81, 0x00}, - {0x82, 0xcd}, - {0x83, 0x01}, - {0x84, 0x01}, - {0x85, 0x01}, - {0x86, 0x29}, - {0x87, 0x01}, - {0x88, 0x68}, - {0x89, 0x01}, - {0x8a, 0x98}, - {0x8b, 0x01}, - {0x8c, 0xe5}, - {0x8d, 0x02}, - {0x8e, 0x1e}, - {0x8f, 0x02}, - {0x90, 0x30}, - {0x91, 0x02}, - {0x92, 0x52}, - {0x93, 0x02}, - {0x94, 0x88}, - {0x95, 0x02}, - {0x96, 0xaa}, - {0x97, 0x02}, - {0x98, 0xd7}, - {0x99, 0x02}, - {0x9a, 0xf7}, - {0x9b, 0x03}, - {0x9c, 0x21}, - {0x9d, 0x03}, - {0x9e, 0x2e}, - {0x9f, 0x03}, - {0xa0, 0x3d}, - {0xa2, 0x03}, - {0xa3, 0x4c}, - {0xa4, 0x03}, - {0xa5, 0x5e}, - {0xa6, 0x03}, - {0xa7, 0x71}, - {0xa9, 0x03}, - {0xaa, 0x86}, - {0xab, 0x03}, - {0xac, 0x94}, - {0xad, 0x03}, - {0xae, 0xfa}, - {0xaf, 0x00}, - {0xb0, 0x00}, - {0xb1, 0x00}, - {0xb2, 0x21}, - {0xb3, 0x00}, - {0xb4, 0x4c}, - {0xb5, 0x00}, - {0xb6, 0x6b}, - {0xb7, 0x00}, - {0xb8, 0x85}, - {0xb9, 0x00}, - {0xba, 0x9a}, - {0xbb, 0x00}, - {0xbc, 0xad}, - {0xbd, 0x00}, - {0xbe, 0xbe}, - {0xbf, 0x00}, - {0xc0, 0xcd}, - {0xc1, 0x01}, - {0xc2, 0x01}, - {0xc3, 0x01}, - {0xc4, 0x29}, - {0xc5, 0x01}, - {0xc6, 0x68}, - {0xc7, 0x01}, - {0xc8, 0x98}, - {0xc9, 0x01}, - {0xca, 0xe5}, - {0xcb, 0x02}, - {0xcc, 0x1e}, - {0xcd, 0x02}, - {0xce, 0x20}, - {0xcf, 0x02}, - {0xd0, 0x52}, - {0xd1, 0x02}, - {0xd2, 0x88}, - {0xd3, 0x02}, - {0xd4, 0xaa}, - {0xd5, 0x02}, - {0xd6, 0xd7}, - {0xd7, 0x02}, - {0xd8, 0xf7}, - {0xd9, 0x03}, - {0xda, 0x21}, - {0xdb, 0x03}, - {0xdc, 0x2e}, - {0xdd, 0x03}, - {0xde, 0x3d}, - {0xdf, 0x03}, - {0xe0, 0x4c}, - {0xe1, 0x03}, - {0xe2, 0x5e}, - {0xe3, 0x03}, - {0xe4, 0x71}, - {0xe5, 0x03}, - {0xe6, 0x86}, - {0xe7, 0x03}, - {0xe8, 0x94}, - {0xe9, 0x03}, - {0xea, 0xfa}, + {0xfb, {0x01}, 0x01}, + {0x00, {0x00}, 0x01}, + {0x01, {0xf4}, 0x01}, + {0x02, {0x00}, 0x01}, + {0x03, {0xef}, 0x01}, + {0x04, {0x01}, 0x01}, + {0x05, {0x07}, 0x01}, + {0x06, {0x01}, 0x01}, + {0x07, {0x28}, 0x01}, + {0x08, {0x01}, 0x01}, + {0x09, {0x44}, 0x01}, + {0x0a, {0x01}, 0x01}, + {0x0b, {0x76}, 0x01}, + {0x0c, {0x01}, 0x01}, + {0x0d, {0xa0}, 0x01}, + {0x0e, {0x01}, 0x01}, + {0x0f, {0xe7}, 0x01}, + {0x10, {0x02}, 0x01}, + {0x11, {0x1f}, 0x01}, + {0x12, {0x02}, 0x01}, + {0x13, {0x22}, 0x01}, + {0x14, {0x02}, 0x01}, + {0x15, {0x54}, 0x01}, + {0x16, {0x02}, 0x01}, + {0x17, {0x8b}, 0x01}, + {0x18, {0x02}, 0x01}, + {0x19, {0xaf}, 0x01}, + {0x1a, {0x02}, 0x01}, + {0x1b, {0xe0}, 0x01}, + {0x1c, {0x03}, 0x01}, + {0x1d, {0x01}, 0x01}, + {0x1e, {0x03}, 0x01}, + {0x1f, {0x2d}, 0x01}, + {0x20, {0x03}, 0x01}, + {0x21, {0x39}, 0x01}, + {0x22, {0x03}, 0x01}, + {0x23, {0x47}, 0x01}, + {0x24, {0x03}, 0x01}, + {0x25, {0x57}, 0x01}, + {0x26, {0x03}, 0x01}, + {0x27, {0x65}, 0x01}, + {0x28, {0x03}, 0x01}, + {0x29, {0x77}, 0x01}, + {0x2a, {0x03}, 0x01}, + {0x2b, {0x85}, 0x01}, + {0x2d, {0x03}, 0x01}, + {0x2f, {0x8f}, 0x01}, + {0x30, {0x03}, 0x01}, + {0x31, {0xcb}, 0x01}, + {0x32, {0x00}, 0x01}, + {0x33, {0xbb}, 0x01}, + {0x34, {0x00}, 0x01}, + {0x35, {0xc0}, 0x01}, + {0x36, {0x00}, 0x01}, + {0x37, {0xcc}, 0x01}, + {0x38, {0x00}, 0x01}, + {0x39, {0xd6}, 0x01}, + {0x3a, {0x00}, 0x01}, + {0x3b, {0xe1}, 0x01}, + {0x3d, {0x00}, 0x01}, + {0x3f, {0xea}, 0x01}, + {0x40, {0x00}, 0x01}, + {0x41, {0xf4}, 0x01}, + {0x42, {0x00}, 0x01}, + {0x43, {0xfe}, 0x01}, + {0x44, {0x01}, 0x01}, + {0x45, {0x07}, 0x01}, + {0x46, {0x01}, 0x01}, + {0x47, {0x28}, 0x01}, + {0x48, {0x01}, 0x01}, + {0x49, {0x44}, 0x01}, + {0x4a, {0x01}, 0x01}, + {0x4b, {0x76}, 0x01}, + {0x4c, {0x01}, 0x01}, + {0x4d, {0xa0}, 0x01}, + {0x4e, {0x01}, 0x01}, + {0x4f, {0xe7}, 0x01}, + {0x50, {0x02}, 0x01}, + {0x51, {0x1f}, 0x01}, + {0x52, {0x02}, 0x01}, + {0x53, {0x22}, 0x01}, + {0x54, {0x02}, 0x01}, + {0x55, {0x54}, 0x01}, + {0x56, {0x02}, 0x01}, + {0x58, {0x8b}, 0x01}, + {0x59, {0x02}, 0x01}, + {0x5a, {0xaf}, 0x01}, + {0x5b, {0x02}, 0x01}, + {0x5c, {0xe0}, 0x01}, + {0x5d, {0x03}, 0x01}, + {0x5e, {0x01}, 0x01}, + {0x5f, {0x03}, 0x01}, + {0x60, {0x2d}, 0x01}, + {0x61, {0x03}, 0x01}, + {0x62, {0x39}, 0x01}, + {0x63, {0x03}, 0x01}, + {0x64, {0x47}, 0x01}, + {0x65, {0x03}, 0x01}, + {0x66, {0x57}, 0x01}, + {0x67, {0x03}, 0x01}, + {0x68, {0x65}, 0x01}, + {0x69, {0x03}, 0x01}, + {0x6a, {0x77}, 0x01}, + {0x6b, {0x03}, 0x01}, + {0x6c, {0x85}, 0x01}, + {0x6d, {0x03}, 0x01}, + {0x6e, {0x8f}, 0x01}, + {0x6f, {0x03}, 0x01}, + {0x70, {0xcb}, 0x01}, + {0x71, {0x00}, 0x01}, + {0x72, {0x00}, 0x01}, + {0x73, {0x00}, 0x01}, + {0x74, {0x21}, 0x01}, + {0x75, {0x00}, 0x01}, + {0x76, {0x4c}, 0x01}, + {0x77, {0x00}, 0x01}, + {0x78, {0x6b}, 0x01}, + {0x79, {0x00}, 0x01}, + {0x7a, {0x85}, 0x01}, + {0x7b, {0x00}, 0x01}, + {0x7c, {0x9a}, 0x01}, + {0x7d, {0x00}, 0x01}, + {0x7e, {0xad}, 0x01}, + {0x7f, {0x00}, 0x01}, + {0x80, {0xbe}, 0x01}, + {0x81, {0x00}, 0x01}, + {0x82, {0xcd}, 0x01}, + {0x83, {0x01}, 0x01}, + {0x84, {0x01}, 0x01}, + {0x85, {0x01}, 0x01}, + {0x86, {0x29}, 0x01}, + {0x87, {0x01}, 0x01}, + {0x88, {0x68}, 0x01}, + {0x89, {0x01}, 0x01}, + {0x8a, {0x98}, 0x01}, + {0x8b, {0x01}, 0x01}, + {0x8c, {0xe5}, 0x01}, + {0x8d, {0x02}, 0x01}, + {0x8e, {0x1e}, 0x01}, + {0x8f, {0x02}, 0x01}, + {0x90, {0x30}, 0x01}, + {0x91, {0x02}, 0x01}, + {0x92, {0x52}, 0x01}, + {0x93, {0x02}, 0x01}, + {0x94, {0x88}, 0x01}, + {0x95, {0x02}, 0x01}, + {0x96, {0xaa}, 0x01}, + {0x97, {0x02}, 0x01}, + {0x98, {0xd7}, 0x01}, + {0x99, {0x02}, 0x01}, + {0x9a, {0xf7}, 0x01}, + {0x9b, {0x03}, 0x01}, + {0x9c, {0x21}, 0x01}, + {0x9d, {0x03}, 0x01}, + {0x9e, {0x2e}, 0x01}, + {0x9f, {0x03}, 0x01}, + {0xa0, {0x3d}, 0x01}, + {0xa2, {0x03}, 0x01}, + {0xa3, {0x4c}, 0x01}, + {0xa4, {0x03}, 0x01}, + {0xa5, {0x5e}, 0x01}, + {0xa6, {0x03}, 0x01}, + {0xa7, {0x71}, 0x01}, + {0xa9, {0x03}, 0x01}, + {0xaa, {0x86}, 0x01}, + {0xab, {0x03}, 0x01}, + {0xac, {0x94}, 0x01}, + {0xad, {0x03}, 0x01}, + {0xae, {0xfa}, 0x01}, + {0xaf, {0x00}, 0x01}, + {0xb0, {0x00}, 0x01}, + {0xb1, {0x00}, 0x01}, + {0xb2, {0x21}, 0x01}, + {0xb3, {0x00}, 0x01}, + {0xb4, {0x4c}, 0x01}, + {0xb5, {0x00}, 0x01}, + {0xb6, {0x6b}, 0x01}, + {0xb7, {0x00}, 0x01}, + {0xb8, {0x85}, 0x01}, + {0xb9, {0x00}, 0x01}, + {0xba, {0x9a}, 0x01}, + {0xbb, {0x00}, 0x01}, + {0xbc, {0xad}, 0x01}, + {0xbd, {0x00}, 0x01}, + {0xbe, {0xbe}, 0x01}, + {0xbf, {0x00}, 0x01}, + {0xc0, {0xcd}, 0x01}, + {0xc1, {0x01}, 0x01}, + {0xc2, {0x01}, 0x01}, + {0xc3, {0x01}, 0x01}, + {0xc4, {0x29}, 0x01}, + {0xc5, {0x01}, 0x01}, + {0xc6, {0x68}, 0x01}, + {0xc7, {0x01}, 0x01}, + {0xc8, {0x98}, 0x01}, + {0xc9, {0x01}, 0x01}, + {0xca, {0xe5}, 0x01}, + {0xcb, {0x02}, 0x01}, + {0xcc, {0x1e}, 0x01}, + {0xcd, {0x02}, 0x01}, + {0xce, {0x20}, 0x01}, + {0xcf, {0x02}, 0x01}, + {0xd0, {0x52}, 0x01}, + {0xd1, {0x02}, 0x01}, + {0xd2, {0x88}, 0x01}, + {0xd3, {0x02}, 0x01}, + {0xd4, {0xaa}, 0x01}, + {0xd5, {0x02}, 0x01}, + {0xd6, {0xd7}, 0x01}, + {0xd7, {0x02}, 0x01}, + {0xd8, {0xf7}, 0x01}, + {0xd9, {0x03}, 0x01}, + {0xda, {0x21}, 0x01}, + {0xdb, {0x03}, 0x01}, + {0xdc, {0x2e}, 0x01}, + {0xdd, {0x03}, 0x01}, + {0xde, {0x3d}, 0x01}, + {0xdf, {0x03}, 0x01}, + {0xe0, {0x4c}, 0x01}, + {0xe1, {0x03}, 0x01}, + {0xe2, {0x5e}, 0x01}, + {0xe3, {0x03}, 0x01}, + {0xe4, {0x71}, 0x01}, + {0xe5, {0x03}, 0x01}, + {0xe6, {0x86}, 0x01}, + {0xe7, {0x03}, 0x01}, + {0xe8, {0x94}, 0x01}, + {0xe9, {0x03}, 0x01}, + {0xea, {0xfa}, 0x01}, /* Select CMD2 Page0 (Undocumented) */ - {0xff, 0x01}, + {0xff, {0x01}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, + {0xfb, {0x01}, 0x01}, /* Select CMD2 Page1 (Undocumented) */ - {0xff, 0x02}, + {0xff, {0x02}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, + {0xfb, {0x01}, 0x01}, /* Select CMD2 Page3 (Undocumented) */ - {0xff, 0x04}, + {0xff, {0x04}, 0x01}, /* Reload CMD1: Don't reload default value to register */ - {0xfb, 0x01}, + {0xfb, {0x01}, 0x01}, /* Select CMD1 */ - {0xff, 0x00}, - {0xd3, 0x22}, /* RGBMIPICTRL: VSYNC back porch = 34 */ - {0xd4, 0x04}, /* RGBMIPICTRL: VSYNC front porch = 4 */ + {0xff, {0x00}, 0x01}, + {0xd3, {0x22}, 0x01}, /* RGBMIPICTRL: VSYNC back porch = 34 */ + {0xd4, {0x04}, 0x01}, /* RGBMIPICTRL: VSYNC front porch = 4 */ +}; + +struct khadas_ts050_panel_data ts050_panel_data = { + .init_code = (struct khadas_ts050_panel_cmd *)ts050_init_code, + .len = ARRAY_SIZE(ts050_init_code) +}; + +struct khadas_ts050_panel_data ts050v2_panel_data = { + .init_code = (struct khadas_ts050_panel_cmd *)ts050v2_init_code, + .len = ARRAY_SIZE(ts050v2_init_code) }; static inline @@ -613,10 +671,11 @@ static int khadas_ts050_panel_prepare(struct drm_panel *panel) msleep(100); - for (i = 0; i < ARRAY_SIZE(init_code); i++) { + for (i = 0; i < khadas_ts050->panel_data->len; i++) { err = mipi_dsi_dcs_write(khadas_ts050->link, - init_code[i].cmd, - &init_code[i].data, 1); + khadas_ts050->panel_data->init_code[i].cmd, + &khadas_ts050->panel_data->init_code[i].data, + khadas_ts050->panel_data->init_code[i].size); if (err < 0) { dev_err(panel->dev, "failed write cmds: %d\n", err); goto poweroff; @@ -762,7 +821,8 @@ static const struct drm_panel_funcs khadas_ts050_panel_funcs = { }; static const struct of_device_id khadas_ts050_of_match[] = { - { .compatible = "khadas,ts050", }, + { .compatible = "khadas,ts050", .data = &ts050_panel_data, }, + { .compatible = "khadas,ts050v2", .data = &ts050v2_panel_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, khadas_ts050_of_match); @@ -806,6 +866,13 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) struct khadas_ts050_panel *khadas_ts050; int err; + const void *data = of_device_get_match_data(&dsi->dev); + + if (!data) { + dev_err(&dsi->dev, "No matching data\n"); + return -ENODEV; + } + dsi->lanes = 4; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | @@ -816,6 +883,7 @@ static int khadas_ts050_panel_probe(struct mipi_dsi_device *dsi) if (!khadas_ts050) return -ENOMEM; + khadas_ts050->panel_data = (struct khadas_ts050_panel_data *)data; mipi_dsi_set_drvdata(dsi, khadas_ts050); khadas_ts050->link = dsi; diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c index 33fb3d715e54..3886372415c2 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36672a.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672a.c @@ -605,21 +605,16 @@ static int nt36672a_panel_add(struct nt36672a_panel *pinfo) struct device *dev = &pinfo->link->dev; int i, ret; - for (i = 0; i < ARRAY_SIZE(pinfo->supplies); i++) + for (i = 0; i < ARRAY_SIZE(pinfo->supplies); i++) { pinfo->supplies[i].supply = nt36672a_regulator_names[i]; + pinfo->supplies[i].init_load_uA = nt36672a_regulator_enable_loads[i]; + } ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pinfo->supplies), pinfo->supplies); if (ret < 0) return dev_err_probe(dev, ret, "failed to get regulators\n"); - for (i = 0; i < ARRAY_SIZE(pinfo->supplies); i++) { - ret = regulator_set_load(pinfo->supplies[i].consumer, - nt36672a_regulator_enable_loads[i]); - if (ret) - return dev_err_probe(dev, ret, "failed to set regulator enable loads\n"); - } - pinfo->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(pinfo->reset_gpio)) return dev_err_probe(dev, PTR_ERR(pinfo->reset_gpio), diff --git a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c index c39fe0fc5d69..20b7bfe4aa12 100644 --- a/drivers/gpu/drm/panel/panel-novatek-nt36672e.c +++ b/drivers/gpu/drm/panel/panel-novatek-nt36672e.c @@ -25,12 +25,6 @@ static const unsigned long regulator_enable_loads[] = { 100000, }; -static const unsigned long regulator_disable_loads[] = { - 80, - 100, - 100, -}; - struct panel_desc { const struct drm_display_mode *display_mode; u32 width_mm; @@ -349,17 +343,7 @@ static int nt36672e_1080x2408_60hz_init(struct mipi_dsi_device *dsi) static int nt36672e_power_on(struct nt36672e_panel *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; - int ret, i; - - for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) { - ret = regulator_set_load(ctx->supplies[i].consumer, - regulator_enable_loads[i]); - if (ret) { - dev_err(&dsi->dev, "regulator set load failed for supply %s: %d\n", - ctx->supplies[i].supply, ret); - return ret; - } - } + int ret; ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret < 0) { @@ -385,20 +369,9 @@ static int nt36672e_power_off(struct nt36672e_panel *ctx) { struct mipi_dsi_device *dsi = ctx->dsi; int ret = 0; - int i; gpiod_set_value(ctx->reset_gpio, 0); - for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) { - ret = regulator_set_load(ctx->supplies[i].consumer, - regulator_disable_loads[i]); - if (ret) { - dev_err(&dsi->dev, "regulator set load failed for supply %s: %d\n", - ctx->supplies[i].supply, ret); - return ret; - } - } - ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); if (ret) dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret); @@ -567,8 +540,10 @@ static int nt36672e_panel_probe(struct mipi_dsi_device *dsi) return -ENODEV; } - for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) + for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) { ctx->supplies[i].supply = regulator_names[i]; + ctx->supplies[i].init_load_uA = regulator_enable_loads[i]; + } ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), ctx->supplies); diff --git a/drivers/gpu/drm/panel/panel-raydium-rm69380.c b/drivers/gpu/drm/panel/panel-raydium-rm69380.c new file mode 100644 index 000000000000..4dca6802faef --- /dev/null +++ b/drivers/gpu/drm/panel/panel-raydium-rm69380.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree. + * Copyright (c) 2024 David Wronek + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include