^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * i.MX drm driver - parallel display implementation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2012 Sascha Hauer, Pengutronix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/component.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/videodev2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <video/of_display_timing.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <drm/drm_atomic_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <drm/drm_bridge.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <drm/drm_fb_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <drm/drm_of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <drm/drm_panel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <drm/drm_probe_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <drm/drm_simple_kms_helper.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "imx-drm.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) struct imx_parallel_display {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct drm_connector connector;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct drm_encoder encoder;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) struct drm_bridge bridge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) void *edid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) u32 bus_format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) u32 bus_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct drm_display_mode mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct drm_panel *panel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct drm_bridge *next_bridge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return container_of(c, struct imx_parallel_display, connector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) static inline struct imx_parallel_display *bridge_to_imxpd(struct drm_bridge *b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return container_of(b, struct imx_parallel_display, bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) static int imx_pd_connector_get_modes(struct drm_connector *connector)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct imx_parallel_display *imxpd = con_to_imxpd(connector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) struct device_node *np = imxpd->dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) int num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) num_modes = drm_panel_get_modes(imxpd->panel, connector);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) if (num_modes > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) return num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (imxpd->edid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) drm_connector_update_edid_property(connector, imxpd->edid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) num_modes = drm_add_edid_modes(connector, imxpd->edid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (np) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) struct drm_display_mode *mode = drm_mode_create(connector->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (!mode)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ret = of_get_drm_display_mode(np, &imxpd->mode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) &imxpd->bus_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) OF_USE_NATIVE_MODE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) drm_mode_copy(mode, &imxpd->mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) drm_mode_probed_add(connector, mode);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) num_modes++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) return num_modes;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static void imx_pd_bridge_enable(struct drm_bridge *bridge)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) drm_panel_prepare(imxpd->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) drm_panel_enable(imxpd->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static void imx_pd_bridge_disable(struct drm_bridge *bridge)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) drm_panel_disable(imxpd->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) drm_panel_unprepare(imxpd->panel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static const u32 imx_pd_bus_fmts[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) MEDIA_BUS_FMT_RGB888_1X24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) MEDIA_BUS_FMT_BGR888_1X24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) MEDIA_BUS_FMT_GBR888_1X24,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) MEDIA_BUS_FMT_RGB666_1X18,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) MEDIA_BUS_FMT_RGB666_1X24_CPADHI,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) MEDIA_BUS_FMT_RGB565_1X16,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) static u32 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) imx_pd_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct drm_bridge_state *bridge_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) struct drm_crtc_state *crtc_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) struct drm_connector_state *conn_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) unsigned int *num_output_fmts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct drm_display_info *di = &conn_state->connector->display_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) u32 *output_fmts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!imxpd->bus_format && !di->num_bus_formats) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) *num_output_fmts = ARRAY_SIZE(imx_pd_bus_fmts);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return kmemdup(imx_pd_bus_fmts, sizeof(imx_pd_bus_fmts),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) *num_output_fmts = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) output_fmts = kmalloc(sizeof(*output_fmts), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) if (!output_fmts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (!imxpd->bus_format && di->num_bus_formats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) output_fmts[0] = di->bus_formats[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) output_fmts[0] = imxpd->bus_format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return output_fmts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) static bool imx_pd_format_supported(u32 output_fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) for (i = 0; i < ARRAY_SIZE(imx_pd_bus_fmts); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) if (imx_pd_bus_fmts[i] == output_fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) static u32 *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) imx_pd_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct drm_bridge_state *bridge_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) struct drm_crtc_state *crtc_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct drm_connector_state *conn_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) u32 output_fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) unsigned int *num_input_fmts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) u32 *input_fmts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) * If the next bridge does not support bus format negotiation, let's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) * use the static bus format definition (imxpd->bus_format) if it's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) * specified, RGB888 when it's not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (output_fmt == MEDIA_BUS_FMT_FIXED)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) output_fmt = imxpd->bus_format ? : MEDIA_BUS_FMT_RGB888_1X24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) /* Now make sure the requested output format is supported. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) if ((imxpd->bus_format && imxpd->bus_format != output_fmt) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) !imx_pd_format_supported(output_fmt)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) *num_input_fmts = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) *num_input_fmts = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) input_fmts = kmalloc(sizeof(*input_fmts), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (!input_fmts)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) input_fmts[0] = output_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) return input_fmts;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) struct drm_bridge_state *bridge_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) struct drm_crtc_state *crtc_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct drm_connector_state *conn_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) struct drm_display_info *di = &conn_state->connector->display_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) struct drm_bridge_state *next_bridge_state = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) struct drm_bridge *next_bridge;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) u32 bus_flags, bus_fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) next_bridge = drm_bridge_get_next_bridge(bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (next_bridge)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) next_bridge_state = drm_atomic_get_new_bridge_state(crtc_state->state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) next_bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (next_bridge_state)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) bus_flags = next_bridge_state->input_bus_cfg.flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) else if (di->num_bus_formats)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) bus_flags = di->bus_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) bus_flags = imxpd->bus_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) bus_fmt = bridge_state->input_bus_cfg.format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) if (!imx_pd_format_supported(bus_fmt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) bridge_state->output_bus_cfg.flags = bus_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) bridge_state->input_bus_cfg.flags = bus_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) imx_crtc_state->bus_flags = bus_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) imx_crtc_state->bus_format = bridge_state->input_bus_cfg.format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) imx_crtc_state->di_hsync_pin = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) imx_crtc_state->di_vsync_pin = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) static const struct drm_connector_funcs imx_pd_connector_funcs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) .fill_modes = drm_helper_probe_single_connector_modes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) .destroy = imx_drm_connector_destroy,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) .reset = drm_atomic_helper_connector_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) .get_modes = imx_pd_connector_get_modes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) .enable = imx_pd_bridge_enable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) .disable = imx_pd_bridge_disable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) .atomic_reset = drm_atomic_helper_bridge_reset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) .atomic_check = imx_pd_bridge_atomic_check,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) .atomic_get_input_bus_fmts = imx_pd_bridge_atomic_get_input_bus_fmts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) .atomic_get_output_bus_fmts = imx_pd_bridge_atomic_get_output_bus_fmts,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) static int imx_pd_register(struct drm_device *drm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) struct imx_parallel_display *imxpd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) struct drm_encoder *encoder = &imxpd->encoder;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* set the connector's dpms to OFF so that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * drm_helper_connector_dpms() won't return
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * immediately since the current state is ON
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * at this point.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_NONE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) imxpd->bridge.funcs = &imx_pd_bridge_funcs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) drm_bridge_attach(encoder, &imxpd->bridge, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (!imxpd->next_bridge) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) drm_connector_helper_add(&imxpd->connector,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) &imx_pd_connector_helper_funcs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) drm_connector_init(drm, &imxpd->connector,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) &imx_pd_connector_funcs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) DRM_MODE_CONNECTOR_DPI);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (imxpd->next_bridge) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) ret = drm_bridge_attach(encoder, imxpd->next_bridge,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) &imxpd->bridge, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) dev_err(imxpd->dev, "failed to attach bridge: %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) drm_connector_attach_encoder(&imxpd->connector, encoder);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static int imx_pd_bind(struct device *dev, struct device *master, void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) struct drm_device *drm = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) struct device_node *np = dev->of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) const u8 *edidp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) struct imx_parallel_display *imxpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) int edid_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) u32 bus_format = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) const char *fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) imxpd = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) memset(imxpd, 0, sizeof(*imxpd));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) /* port@1 is the output port */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) ret = drm_of_find_panel_or_bridge(np, 1, 0, &imxpd->panel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) &imxpd->next_bridge);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) if (ret && ret != -ENODEV)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) edidp = of_get_property(np, "edid", &edid_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) if (edidp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) imxpd->edid = devm_kmemdup(dev, edidp, edid_len, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (!strcmp(fmt, "rgb24"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) bus_format = MEDIA_BUS_FMT_RGB888_1X24;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) else if (!strcmp(fmt, "rgb565"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) bus_format = MEDIA_BUS_FMT_RGB565_1X16;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) else if (!strcmp(fmt, "bgr666"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) bus_format = MEDIA_BUS_FMT_RGB666_1X18;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) else if (!strcmp(fmt, "lvds666"))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) imxpd->bus_format = bus_format;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) imxpd->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ret = imx_pd_register(drm, imxpd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) static const struct component_ops imx_pd_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) .bind = imx_pd_bind,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) static int imx_pd_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) struct imx_parallel_display *imxpd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) if (!imxpd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) platform_set_drvdata(pdev, imxpd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return component_add(&pdev->dev, &imx_pd_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static int imx_pd_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) component_del(&pdev->dev, &imx_pd_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static const struct of_device_id imx_pd_dt_ids[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) { .compatible = "fsl,imx-parallel-display", },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) { /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) static struct platform_driver imx_pd_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) .probe = imx_pd_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) .remove = imx_pd_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) .of_match_table = imx_pd_dt_ids,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) .name = "imx-parallel-display",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) module_platform_driver(imx_pd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) MODULE_DESCRIPTION("i.MX parallel display driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) MODULE_AUTHOR("Sascha Hauer, Pengutronix");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) MODULE_ALIAS("platform:imx-parallel-display");