summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2024-06-21 10:31:14 +1000
committerDave Airlie <airlied@redhat.com>2024-06-21 10:31:27 +1000
commit6dac16124c07a9a4313ccb5f10b1c3cc42ddfda7 (patch)
tree98cbd203dbe645d3c0c1fae3d4816bf4dad34a40
parentf680df51ca5f4ab364c9bbfcdbd2737e32092454 (diff)
parent310ec03841a36e3f45fb528f0dfdfe5b9e84b037 (diff)
downloadlinux-6dac16124c07a9a4313ccb5f10b1c3cc42ddfda7.tar.gz
linux-6dac16124c07a9a4313ccb5f10b1c3cc42ddfda7.tar.bz2
linux-6dac16124c07a9a4313ccb5f10b1c3cc42ddfda7.zip
Merge tag 'drm-misc-next-2024-06-06' of https://gitlab.freedesktop.org/drm/misc/kernel into drm-next
drm-misc-next for 6.10: UAPI Changes: Cross-subsystem Changes: - dma-buf: Warn when reserving 0 fence slots, internal API enhancements for heaps Core Changes: Driver Changes: - atmel-hlcdc: Support XLCDC in sam9x7 - msm: Validate registers XML description against schema in CI - v3d: Fix build warning - bridges: - analogix_dp: Various improvements - panels: - New panel: WL-355608-A8 Signed-off-by: Dave Airlie <airlied@redhat.com> From: Maxime Ripard <mripard@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20240606-vivid-amphibian-jackrabbit-40b1d1@houat
-rw-r--r--Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml60
-rw-r--r--MAINTAINERS1
-rw-r--r--drivers/dma-buf/dma-heap.c4
-rw-r--r--drivers/dma-buf/dma-resv.c7
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c172
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c105
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h132
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c369
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.c152
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_core.h22
-rw-r--r--drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c119
-rw-r--r--drivers/gpu/drm/ci/build.sh3
-rw-r--r--drivers/gpu/drm/ci/build.yml1
-rw-r--r--drivers/gpu/drm/panel/panel-newvision-nv3052c.c225
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.c4
-rw-r--r--drivers/gpu/drm/v3d/v3d_drv.h3
-rw-r--r--drivers/gpu/drm/v3d/v3d_perfmon.c204
-rw-r--r--drivers/gpu/drm/v3d/v3d_performance_counters.h189
-rw-r--r--include/linux/mfd/atmel-hlcdc.h10
-rw-r--r--include/uapi/linux/dma-heap.h2
20 files changed, 1230 insertions, 554 deletions
diff --git a/Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml b/Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml
new file mode 100644
index 000000000000..e552d01b52b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/wl-355608-a8.yaml
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/wl-355608-a8.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: WL-355608-A8 3.5" (640x480 pixels) 24-bit IPS LCD panel
+
+maintainers:
+ - Ryan Walklin <ryan@testtoast.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+ - $ref: /schemas/spi/spi-peripheral-props.yaml#
+
+properties:
+ compatible:
+ const: wl-355608-a8
+
+ reg:
+ maxItems: 1
+
+ spi-3wire: true
+
+required:
+ - compatible
+ - reg
+ - port
+ - power-supply
+ - reset-gpios
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ spi {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ panel@0 {
+ compatible = "wl-355608-a8";
+ reg = <0>;
+
+ spi-3wire;
+ spi-max-frequency = <3125000>;
+
+ reset-gpios = <&pio 8 14 GPIO_ACTIVE_LOW>; // PI14
+
+ backlight = <&backlight>;
+ power-supply = <&reg_lcd>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&tcon_lcd0_out_lcd>;
+ };
+ };
+ };
+ };
diff --git a/MAINTAINERS b/MAINTAINERS
index b333782bdd83..6a1660480782 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7566,7 +7566,6 @@ F: include/drm/gpu_scheduler.h
DRM PANEL DRIVERS
M: Neil Armstrong <neil.armstrong@linaro.org>
R: Jessica Zhang <quic_jesszhan@quicinc.com>
-R: Sam Ravnborg <sam@ravnborg.org>
L: dri-devel@lists.freedesktop.org
S: Maintained
T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
index 84ae708fafe7..2298ca5e112e 100644
--- a/drivers/dma-buf/dma-heap.c
+++ b/drivers/dma-buf/dma-heap.c
@@ -50,8 +50,8 @@ static struct class *dma_heap_class;
static DEFINE_XARRAY_ALLOC(dma_heap_minors);
static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
- unsigned int fd_flags,
- unsigned int heap_flags)
+ u32 fd_flags,
+ u64 heap_flags)
{
struct dma_buf *dmabuf;
int fd;
diff --git a/drivers/dma-buf/dma-resv.c b/drivers/dma-buf/dma-resv.c
index e2869fb31140..5f8d010516f0 100644
--- a/drivers/dma-buf/dma-resv.c
+++ b/drivers/dma-buf/dma-resv.c
@@ -186,6 +186,13 @@ int dma_resv_reserve_fences(struct dma_resv *obj, unsigned int num_fences)
dma_resv_assert_held(obj);
+ /* Driver and component code should never call this function with
+ * num_fences=0. If they do it usually points to bugs when calculating
+ * the number of needed fences dynamically.
+ */
+ if (WARN_ON(!num_fences))
+ return -EINVAL;
+
old = dma_resv_fences_list(obj);
if (old && old->max_fences) {
if ((old->num_fences + num_fences) <= old->max_fences)
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
index cc5cf4c2faf7..0f7ffb3ced20 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -30,10 +30,12 @@
*
* @base: base CRTC state
* @output_mode: RGBXXX output mode
+ * @dpi: output DPI mode
*/
struct atmel_hlcdc_crtc_state {
struct drm_crtc_state base;
unsigned int output_mode;
+ u8 dpi;
};
static inline struct atmel_hlcdc_crtc_state *
@@ -164,18 +166,24 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)
state = drm_crtc_state_to_atmel_hlcdc_crtc_state(c->state);
cfg = state->output_mode << 8;
- if (adj->flags & DRM_MODE_FLAG_NVSYNC)
- cfg |= ATMEL_HLCDC_VSPOL;
+ if (!crtc->dc->desc->is_xlcdc) {
+ if (adj->flags & DRM_MODE_FLAG_NVSYNC)
+ cfg |= ATMEL_HLCDC_VSPOL;
- if (adj->flags & DRM_MODE_FLAG_NHSYNC)
- cfg |= ATMEL_HLCDC_HSPOL;
+ if (adj->flags & DRM_MODE_FLAG_NHSYNC)
+ cfg |= ATMEL_HLCDC_HSPOL;
+ } else {
+ cfg |= state->dpi << 11;
+ }
regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
- ATMEL_HLCDC_GUARDTIME_MASK | ATMEL_HLCDC_MODE_MASK,
+ ATMEL_HLCDC_GUARDTIME_MASK |
+ (crtc->dc->desc->is_xlcdc ? ATMEL_XLCDC_MODE_MASK |
+ ATMEL_XLCDC_DPI : ATMEL_HLCDC_MODE_MASK),
cfg);
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
@@ -202,20 +210,37 @@ static void atmel_hlcdc_crtc_atomic_disable(struct drm_crtc *c,
pm_runtime_get_sync(dev->dev);
+ if (crtc->dc->desc->is_xlcdc) {
+ regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_XLCDC_CM);
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ !(status & ATMEL_XLCDC_CM),
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register CMSTS timeout\n");
+
+ regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_XLCDC_SD);
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ status & ATMEL_XLCDC_SD,
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register SDSTS timeout\n");
+ }
+
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
- while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
- (status & ATMEL_HLCDC_DISP))
- cpu_relax();
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ !(status & ATMEL_HLCDC_DISP),
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register DISPSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
- while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
- (status & ATMEL_HLCDC_SYNC))
- cpu_relax();
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ !(status & ATMEL_HLCDC_SYNC),
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register LCDSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
- while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
- (status & ATMEL_HLCDC_PIXEL_CLK))
- cpu_relax();
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ !(status & ATMEL_HLCDC_PIXEL_CLK),
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register CLKSTS timeout\n");
clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
pinctrl_pm_select_sleep_state(dev->dev);
@@ -241,30 +266,95 @@ static void atmel_hlcdc_crtc_atomic_enable(struct drm_crtc *c,
clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
- while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
- !(status & ATMEL_HLCDC_PIXEL_CLK))
- cpu_relax();
-
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ status & ATMEL_HLCDC_PIXEL_CLK,
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register CLKSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
- while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
- !(status & ATMEL_HLCDC_SYNC))
- cpu_relax();
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ status & ATMEL_HLCDC_SYNC,
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register LCDSTS timeout\n");
regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
- while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
- !(status & ATMEL_HLCDC_DISP))
- cpu_relax();
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ status & ATMEL_HLCDC_DISP,
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register DISPSTS timeout\n");
+
+ if (crtc->dc->desc->is_xlcdc) {
+ regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_XLCDC_CM);
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ status & ATMEL_XLCDC_CM,
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register CMSTS timeout\n");
+
+ regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_XLCDC_SD);
+ if (regmap_read_poll_timeout(regmap, ATMEL_HLCDC_SR, status,
+ !(status & ATMEL_XLCDC_SD),
+ 10, 1000))
+ dev_warn(dev->dev, "Atmel LCDC status register SDSTS timeout\n");
+ }
pm_runtime_put_sync(dev->dev);
}
-#define ATMEL_HLCDC_RGB444_OUTPUT BIT(0)
-#define ATMEL_HLCDC_RGB565_OUTPUT BIT(1)
-#define ATMEL_HLCDC_RGB666_OUTPUT BIT(2)
-#define ATMEL_HLCDC_RGB888_OUTPUT BIT(3)
-#define ATMEL_HLCDC_OUTPUT_MODE_MASK GENMASK(3, 0)
+#define ATMEL_HLCDC_RGB444_OUTPUT BIT(0)
+#define ATMEL_HLCDC_RGB565_OUTPUT BIT(1)
+#define ATMEL_HLCDC_RGB666_OUTPUT BIT(2)
+#define ATMEL_HLCDC_RGB888_OUTPUT BIT(3)
+#define ATMEL_HLCDC_DPI_RGB565C1_OUTPUT BIT(4)
+#define ATMEL_HLCDC_DPI_RGB565C2_OUTPUT BIT(5)
+#define ATMEL_HLCDC_DPI_RGB565C3_OUTPUT BIT(6)
+#define ATMEL_HLCDC_DPI_RGB666C1_OUTPUT BIT(7)
+#define ATMEL_HLCDC_DPI_RGB666C2_OUTPUT BIT(8)
+#define ATMEL_HLCDC_DPI_RGB888_OUTPUT BIT(9)
+#define ATMEL_HLCDC_OUTPUT_MODE_MASK GENMASK(3, 0)
+#define ATMEL_XLCDC_OUTPUT_MODE_MASK GENMASK(9, 0)
+
+static int atmel_xlcdc_connector_output_dsi(struct drm_encoder *encoder,
+ struct drm_display_info *info)
+{
+ int j;
+ unsigned int supported_fmts = 0;
+
+ switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
+ case 0:
+ break;
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ return ATMEL_HLCDC_DPI_RGB565C1_OUTPUT;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ return ATMEL_HLCDC_DPI_RGB666C1_OUTPUT;
+ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+ return ATMEL_HLCDC_DPI_RGB666C2_OUTPUT;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ return ATMEL_HLCDC_DPI_RGB888_OUTPUT;
+ default:
+ return -EINVAL;
+ }
+
+ for (j = 0; j < info->num_bus_formats; j++) {
+ switch (info->bus_formats[j]) {
+ case MEDIA_BUS_FMT_RGB565_1X16:
+ supported_fmts |= ATMEL_HLCDC_DPI_RGB565C1_OUTPUT;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ supported_fmts |= ATMEL_HLCDC_DPI_RGB666C1_OUTPUT;
+ break;
+ case MEDIA_BUS_FMT_RGB666_1X24_CPADHI:
+ supported_fmts |= ATMEL_HLCDC_DPI_RGB666C2_OUTPUT;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ supported_fmts |= ATMEL_HLCDC_DPI_RGB888_OUTPUT;
+ break;
+ default:
+ break;
+ }
+ }
+ return supported_fmts;
+}
static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
{
@@ -277,6 +367,13 @@ static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
encoder = state->best_encoder;
if (!encoder)
encoder = connector->encoder;
+ /*
+ * atmel-hlcdc to support DSI formats with DSI video pipeline
+ * when DRM_MODE_ENCODER_DSI type is set by
+ * connector driver component.
+ */
+ if (encoder->encoder_type == DRM_MODE_ENCODER_DSI)
+ return atmel_xlcdc_connector_output_dsi(encoder, info);
switch (atmel_hlcdc_encoder_get_bus_fmt(encoder)) {
case 0:
@@ -317,7 +414,7 @@ static int atmel_hlcdc_connector_output_mode(struct drm_connector_state *state)
static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
{
- unsigned int output_fmts = ATMEL_HLCDC_OUTPUT_MODE_MASK;
+ unsigned int output_fmts;
struct atmel_hlcdc_crtc_state *hstate;
struct drm_connector_state *cstate;
struct drm_connector *connector;
@@ -325,6 +422,8 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
int i;
crtc = drm_crtc_to_atmel_hlcdc_crtc(state->crtc);
+ output_fmts = crtc->dc->desc->is_xlcdc ? ATMEL_XLCDC_OUTPUT_MODE_MASK :
+ ATMEL_HLCDC_OUTPUT_MODE_MASK;
for_each_new_connector_in_state(state->state, connector, cstate, i) {
unsigned int supported_fmts = 0;
@@ -345,7 +444,15 @@ static int atmel_hlcdc_crtc_select_output_mode(struct drm_crtc_state *state)
hstate = drm_crtc_state_to_atmel_hlcdc_crtc_state(state);
hstate->output_mode = fls(output_fmts) - 1;
-
+ if (crtc->dc->desc->is_xlcdc) {
+ /* check if MIPI DPI bit needs to be set */
+ if (fls(output_fmts) > 3) {
+ hstate->output_mode -= 4;
+ hstate->dpi = 1;
+ } else {
+ hstate->dpi = 0;
+ }
+ }
return 0;
}
@@ -449,6 +556,7 @@ static struct drm_crtc_state *
atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc)
{
struct atmel_hlcdc_crtc_state *state, *cur;
+ struct atmel_hlcdc_crtc *c = drm_crtc_to_atmel_hlcdc_crtc(crtc);
if (WARN_ON(!crtc->state))
return NULL;
@@ -460,6 +568,8 @@ atmel_hlcdc_crtc_duplicate_state(struct drm_crtc *crtc)
cur = drm_crtc_state_to_atmel_hlcdc_crtc_state(crtc->state);
state->output_mode = cur->output_mode;
+ if (c->dc->desc->is_xlcdc)
+ state->dpi = cur->dpi;
return &state->base;
}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
index 84c54e8622d1..9ce429f889ca 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -58,6 +58,7 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9n12 = {
.conflicting_output_formats = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9n12_layers),
.layers = atmel_hlcdc_at91sam9n12_layers,
+ .ops = &atmel_hlcdc_ops,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_at91sam9x5_layers[] = {
@@ -151,6 +152,7 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_at91sam9x5 = {
.conflicting_output_formats = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_at91sam9x5_layers),
.layers = atmel_hlcdc_at91sam9x5_layers,
+ .ops = &atmel_hlcdc_ops,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
@@ -269,6 +271,7 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
.conflicting_output_formats = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
.layers = atmel_hlcdc_sama5d3_layers,
+ .ops = &atmel_hlcdc_ops,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d4_layers[] = {
@@ -364,6 +367,7 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d4 = {
.max_hpw = 0x3ff,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d4_layers),
.layers = atmel_hlcdc_sama5d4_layers,
+ .ops = &atmel_hlcdc_ops,
};
static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sam9x60_layers[] = {
@@ -460,6 +464,103 @@ static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sam9x60 = {
.fixed_clksrc = true,
.nlayers = ARRAY_SIZE(atmel_hlcdc_sam9x60_layers),
.layers = atmel_hlcdc_sam9x60_layers,
+ .ops = &atmel_hlcdc_ops,
+};
+
+static const struct atmel_hlcdc_layer_desc atmel_xlcdc_sam9x75_layers[] = {
+ {
+ .name = "base",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x60,
+ .id = 0,
+ .type = ATMEL_HLCDC_BASE_LAYER,
+ .cfgs_offset = 0x1c,
+ .layout = {
+ .xstride = { 2 },
+ .default_color = 3,
+ .general_config = 4,
+ .disc_pos = 5,
+ .disc_size = 6,
+ },
+ .clut_offset = 0x700,
+ },
+ {
+ .name = "overlay1",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x160,
+ .id = 1,
+ .type = ATMEL_HLCDC_OVERLAY_LAYER,
+ .cfgs_offset = 0x1c,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .xstride = { 4 },
+ .pstride = { 5 },
+ .default_color = 6,
+ .chroma_key = 7,
+ .chroma_key_mask = 8,
+ .general_config = 9,
+ },
+ .clut_offset = 0xb00,
+ },
+ {
+ .name = "overlay2",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x260,
+ .id = 2,
+ .type = ATMEL_HLCDC_OVERLAY_LAYER,
+ .cfgs_offset = 0x1c,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .xstride = { 4 },
+ .pstride = { 5 },
+ .default_color = 6,
+ .chroma_key = 7,
+ .chroma_key_mask = 8,
+ .general_config = 9,
+ },
+ .clut_offset = 0xf00,
+ },
+ {
+ .name = "high-end-overlay",
+ .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+ .regs_offset = 0x360,
+ .id = 3,
+ .type = ATMEL_HLCDC_OVERLAY_LAYER,
+ .cfgs_offset = 0x30,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .memsize = 4,
+ .xstride = { 5, 7 },
+ .pstride = { 6, 8 },
+ .default_color = 9,
+ .chroma_key = 10,
+ .chroma_key_mask = 11,
+ .general_config = 12,
+ .csc = 16,
+ .scaler_config = 23,
+ .vxs_config = 30,
+ .hxs_config = 31,
+ },
+ .clut_offset = 0x1300,
+ },
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_xlcdc_dc_sam9x75 = {
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 2048,
+ .max_height = 2048,
+ .max_spw = 0x3ff,
+ .max_vpw = 0x3ff,
+ .max_hpw = 0x3ff,
+ .fixed_clksrc = true,
+ .is_xlcdc = true,
+ .nlayers = ARRAY_SIZE(atmel_xlcdc_sam9x75_layers),
+ .layers = atmel_xlcdc_sam9x75_layers,
+ .ops = &atmel_xlcdc_ops,
};
static const struct of_device_id atmel_hlcdc_of_match[] = {
@@ -487,6 +588,10 @@ static const struct of_device_id atmel_hlcdc_of_match[] = {
.compatible = "microchip,sam9x60-hlcdc",
.data = &atmel_hlcdc_dc_sam9x60,
},
+ {
+ .compatible = "microchip,sam9x75-xlcdc",
+ .data = &atmel_xlcdc_dc_sam9x75,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, atmel_hlcdc_of_match);
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
index 5b5c774e0edf..e1a0bb24b511 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -15,6 +15,7 @@
#include <drm/drm_plane.h>
+/* LCD controller common registers */
#define ATMEL_HLCDC_LAYER_CHER 0x0
#define ATMEL_HLCDC_LAYER_CHDR 0x4
#define ATMEL_HLCDC_LAYER_CHSR 0x8
@@ -128,6 +129,47 @@
#define ATMEL_HLCDC_MAX_LAYERS 6
+/* XLCDC controller specific registers */
+#define ATMEL_XLCDC_LAYER_ENR 0x10
+#define ATMEL_XLCDC_LAYER_EN BIT(0)
+
+#define ATMEL_XLCDC_LAYER_IER 0x0
+#define ATMEL_XLCDC_LAYER_IDR 0x4
+#define ATMEL_XLCDC_LAYER_ISR 0xc
+#define ATMEL_XLCDC_LAYER_OVR_IRQ(p) BIT(2 + (8 * (p)))
+
+#define ATMEL_XLCDC_LAYER_PLANE_ADDR(p) (((p) * 0x4) + 0x18)
+
+#define ATMEL_XLCDC_LAYER_DMA_CFG 0
+
+#define ATMEL_XLCDC_LAYER_DMA BIT(0)
+#define ATMEL_XLCDC_LAYER_REP BIT(1)
+#define ATMEL_XLCDC_LAYER_DISCEN BIT(4)
+
+#define ATMEL_XLCDC_LAYER_SFACTC_A0_MULT_AS (4 << 6)
+#define ATMEL_XLCDC_LAYER_SFACTA_ONE BIT(9)
+#define ATMEL_XLCDC_LAYER_DFACTC_M_A0_MULT_AS (6 << 11)
+#define ATMEL_XLCDC_LAYER_DFACTA_ONE BIT(14)
+
+#define ATMEL_XLCDC_LAYER_A0_SHIFT 16
+#define ATMEL_XLCDC_LAYER_A0(x) \
+ ((x) << ATMEL_XLCDC_LAYER_A0_SHIFT)
+
+#define ATMEL_XLCDC_LAYER_VSCALER_LUMA_ENABLE BIT(0)
+#define ATMEL_XLCDC_LAYER_VSCALER_CHROMA_ENABLE BIT(1)
+#define ATMEL_XLCDC_LAYER_HSCALER_LUMA_ENABLE BIT(4)
+#define ATMEL_XLCDC_LAYER_HSCALER_CHROMA_ENABLE BIT(5)
+
+#define ATMEL_XLCDC_LAYER_VXSYCFG_ONE BIT(0)
+#define ATMEL_XLCDC_LAYER_VXSYTAP2_ENABLE BIT(4)
+#define ATMEL_XLCDC_LAYER_VXSCCFG_ONE BIT(16)
+#define ATMEL_XLCDC_LAYER_VXSCTAP2_ENABLE BIT(20)
+
+#define ATMEL_XLCDC_LAYER_HXSYCFG_ONE BIT(0)
+#define ATMEL_XLCDC_LAYER_HXSYTAP2_ENABLE BIT(4)
+#define ATMEL_XLCDC_LAYER_HXSCCFG_ONE BIT(16)
+#define ATMEL_XLCDC_LAYER_HXSCTAP2_ENABLE BIT(20)
+
/**
* Atmel HLCDC Layer registers layout structure
*
@@ -156,6 +198,8 @@
* @disc_pos: discard area position register
* @disc_size: discard area size register
* @csc: color space conversion register
+ * @vxs_config: vertical scalar filter taps control register
+ * @hxs_config: horizontal scalar filter taps control register
*/
struct atmel_hlcdc_layer_cfg_layout {
int xstride[ATMEL_HLCDC_LAYER_MAX_PLANES];
@@ -175,6 +219,8 @@ struct atmel_hlcdc_layer_cfg_layout {
int disc_pos;
int disc_size;
int csc;
+ int vxs_config;
+ int hxs_config;
};
/**
@@ -289,6 +335,64 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *layer)
}
/**
+ * struct atmel_hlcdc_dc - Atmel HLCDC Display Controller.
+ * @desc: HLCDC Display Controller description
+ * @dscrpool: DMA coherent pool used to allocate DMA descriptors
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @crtc: CRTC provided by the display controller
+ * @layers: active HLCDC layers
+ * @suspend: used to store the HLCDC state when entering suspend
+ * @suspend.imr: used to read/write LCDC Interrupt Mask Register
+ * @suspend.state: Atomic commit structure
+ */
+struct atmel_hlcdc_dc {
+ const struct atmel_hlcdc_dc_desc *desc;
+ struct dma_pool *dscrpool;
+ struct atmel_hlcdc *hlcdc;
+ struct drm_crtc *crtc;
+ struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
+ struct {
+ u32 imr;
+ struct drm_atomic_state *state;
+ } suspend;
+};
+
+struct atmel_hlcdc_plane_state;
+
+/**
+ * struct atmel_lcdc_dc_ops - describes atmel_lcdc ops group
+ * to differentiate HLCDC and XLCDC IP code support
+ * @plane_setup_scaler: update the vertical and horizontal scaling factors
+ * @update_lcdc_buffers: update the each LCDC layers DMA registers
+ * @lcdc_atomic_disable: disable LCDC interrupts and layers
+ * @lcdc_update_general_settings: update each LCDC layers general
+ * configuration register
+ * @lcdc_atomic_update: enable the LCDC layers and interrupts
+ * @lcdc_csc_init: update the color space conversion co-efficient of
+ * High-end overlay register
+ * @lcdc_irq_dbg: to raise alert incase of interrupt overrun in any LCDC layer
+ */
+struct atmel_lcdc_dc_ops {
+ void (*plane_setup_scaler)(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state);
+ void (*lcdc_update_buffers)(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state,
+ u32 sr, int i);
+ void (*lcdc_atomic_disable)(struct atmel_hlcdc_plane *plane);
+ void (*lcdc_update_general_settings)(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state);
+ void (*lcdc_atomic_update)(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_dc *dc);
+ void (*lcdc_csc_init)(struct atmel_hlcdc_plane *plane,
+ const struct atmel_hlcdc_layer_desc *desc);
+ void (*lcdc_irq_dbg)(struct atmel_hlcdc_plane *plane,
+ const struct atmel_hlcdc_layer_desc *desc);
+};
+
+extern const struct atmel_lcdc_dc_ops atmel_hlcdc_ops;
+extern const struct atmel_lcdc_dc_ops atmel_xlcdc_ops;
+
+/**
* Atmel HLCDC Display Controller description structure.
*
* This structure describes the HLCDC IP capabilities and depends on the
@@ -304,8 +408,10 @@ atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *layer)
* @conflicting_output_formats: true if RGBXXX output formats conflict with
* each other.
* @fixed_clksrc: true if clock source is fixed
+ * @is_xlcdc: true if XLCDC IP is supported
* @layers: a layer description table describing available layers
* @nlayers: layer description table size
+ * @ops: atmel lcdc dc ops
*/
struct atmel_hlcdc_dc_desc {
int min_width;
@@ -317,32 +423,10 @@ struct atmel_hlcdc_dc_desc {
int max_hpw;
bool conflicting_output_formats;
bool fixed_clksrc;
+ bool is_xlcdc;
const struct atmel_hlcdc_layer_desc *layers;
int nlayers;
-};
-
-/**
- * Atmel HLCDC Display Controller.
- *
- * @desc: HLCDC Display Controller description
- * @dscrpool: DMA coherent pool used to allocate DMA descriptors
- * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
- * @fbdev: framebuffer device attached to the Display Controller
- * @crtc: CRTC provided by the display controller
- * @planes: instantiated planes
- * @layers: active HLCDC layers
- * @suspend: used to store the HLCDC state when entering suspend
- */
-struct atmel_hlcdc_dc {
- const struct atmel_hlcdc_dc_desc *desc;
- struct dma_pool *dscrpool;
- struct atmel_hlcdc *hlcdc;
- struct drm_crtc *crtc;
- struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
- struct {
- u32 imr;
- struct drm_atomic_state *state;
- } suspend;
+ const struct atmel_lcdc_dc_ops *ops;
};
extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
index daa508504f47..4a7ba0918eca 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -282,8 +282,9 @@ atmel_hlcdc_plane_scaler_set_phicoeff(struct atmel_hlcdc_plane *plane,
coeff_tab[i]);
}
-static void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
+static
+void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state)
{
const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
u32 xfactor, yfactor;
@@ -330,11 +331,61 @@ static void atmel_hlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
yfactor));
}
+static
+void atmel_xlcdc_plane_setup_scaler(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state)
+{
+ const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
+ u32 xfactor, yfactor;
+
+ if (!desc->layout.scaler_config)
+ return;
+
+ if (state->crtc_w == state->src_w && state->crtc_h == state->src_h) {
+ atmel_hlcdc_layer_write_cfg(&plane->layer,
+ desc->layout.scaler_config, 0);
+ return;
+ }
+
+ /* xfactor = round[(2^20 * XMEMSIZE)/XSIZE)] */
+ xfactor = (u32)(((1 << 20) * state->src_w) / state->crtc_w);
+
+ /* yfactor = round[(2^20 * YMEMSIZE)/YSIZE)] */
+ yfactor = (u32)(((1 << 20) * state->src_h) / state->crtc_h);
+
+ atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config,
+ ATMEL_XLCDC_LAYER_VSCALER_LUMA_ENABLE |
+ ATMEL_XLCDC_LAYER_VSCALER_CHROMA_ENABLE |
+ ATMEL_XLCDC_LAYER_HSCALER_LUMA_ENABLE |
+ ATMEL_XLCDC_LAYER_HSCALER_CHROMA_ENABLE);
+
+ atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 1,
+ yfactor);
+ atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 3,
+ xfactor);
+
+ /*
+ * With YCbCr 4:2:2 and YCbYcr 4:2:0 window resampling, configuration
+ * register LCDC_HEOCFG25.VXSCFACT and LCDC_HEOCFG27.HXSCFACT is half
+ * the value of yfactor and xfactor.
+ */
+ if (state->base.fb->format->format == DRM_FORMAT_YUV420) {
+ yfactor /= 2;
+ xfactor /= 2;
+ }
+
+ atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 2,
+ yfactor);
+ atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.scaler_config + 4,
+ xfactor);
+}
+
static void
atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
struct atmel_hlcdc_plane_state *state)
{
const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
+ struct atmel_hlcdc_dc *dc = plane->base.dev->dev_private;
if (desc->layout.size)
atmel_hlcdc_layer_write_cfg(&plane->layer, desc->layout.size,
@@ -352,12 +403,12 @@ atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
ATMEL_HLCDC_LAYER_POS(state->crtc_x,
state->crtc_y));
- atmel_hlcdc_plane_setup_scaler(plane, state);
+ dc->desc->ops->plane_setup_scaler(plane, state);
}
-static void
-atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
- struct atmel_hlcdc_plane_state *state)
+static
+void atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state)
{
unsigned int cfg = ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id;
const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
@@ -393,6 +444,40 @@ atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
cfg);
}
+static
+void atmel_xlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_state *state)
+{
+ const struct atmel_hlcdc_layer_desc *desc = plane->layer.desc;
+ const struct drm_format_info *format = state->base.fb->format;
+ unsigned int cfg;
+
+ atmel_hlcdc_layer_write_cfg(&plane->layer, ATMEL_XLCDC_LAYER_DMA_CFG,
+ ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 | state->ahb_id);
+
+ cfg = ATMEL_XLCDC_LAYER_DMA | ATMEL_XLCDC_LAYER_REP;
+
+ if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
+ /*
+ * Alpha Blending bits specific to SAM9X7 SoC
+ */
+ cfg |= ATMEL_XLCDC_LAYER_SFACTC_A0_MULT_AS |
+ ATMEL_XLCDC_LAYER_SFACTA_ONE |
+ ATMEL_XLCDC_LAYER_DFACTC_M_A0_MULT_AS |
+ ATMEL_XLCDC_LAYER_DFACTA_ONE;
+ if (format->has_alpha)