#include <drm/drm_panel.h>
#include <video/display_timing.h>
+#include <video/of_display_timing.h>
#include <video/videomode.h>
struct panel_desc {
bool prepared;
bool enabled;
+ struct device *dev;
const struct panel_desc *desc;
struct backlight_device *backlight;
return num;
}
+static int panel_simple_of_get_native_mode(struct panel_simple *panel)
+{
+ struct drm_connector *connector = panel->base.connector;
+ struct drm_device *drm = panel->base.drm;
+ struct drm_display_mode *mode;
+ struct device_node *timings_np;
+ int ret;
+
+ timings_np = of_get_child_by_name(panel->dev->of_node,
+ "display-timings");
+ if (!timings_np) {
+ dev_dbg(panel->dev, "failed to find display-timings node\n");
+ return 0;
+ }
+
+ of_node_put(timings_np);
+ mode = drm_mode_create(drm);
+ if (!mode)
+ return 0;
+
+ ret = of_get_drm_display_mode(panel->dev->of_node, mode,
+ OF_USE_NATIVE_MODE);
+ if (ret) {
+ dev_dbg(panel->dev, "failed to find dts display timings\n");
+ drm_mode_destroy(drm, mode);
+ return 0;
+ }
+
+ drm_mode_set_name(mode);
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+ drm_mode_probed_add(connector, mode);
+
+ return 1;
+}
+
static int panel_simple_disable(struct drm_panel *panel)
{
struct panel_simple *p = to_panel_simple(panel);
backlight_update_status(p->backlight);
}
- if (p->desc->delay.disable)
+ if (p->desc && p->desc->delay.disable)
msleep(p->desc->delay.disable);
p->enabled = false;
return 0;
if (p->enable_gpio)
- gpiod_set_value_cansleep(p->enable_gpio, 0);
+ gpiod_direction_output(p->enable_gpio, 0);
regulator_disable(p->supply);
- if (p->desc->delay.unprepare)
+ if (p->desc && p->desc->delay.unprepare)
msleep(p->desc->delay.unprepare);
p->prepared = false;
}
if (p->enable_gpio)
- gpiod_set_value_cansleep(p->enable_gpio, 1);
+ gpiod_direction_output(p->enable_gpio, 1);
- if (p->desc->delay.prepare)
+ if (p->desc && p->desc->delay.prepare)
msleep(p->desc->delay.prepare);
p->prepared = true;
if (p->enabled)
return 0;
- if (p->desc->delay.enable)
+ if (p->desc && p->desc->delay.enable)
msleep(p->desc->delay.enable);
if (p->backlight) {
struct panel_simple *p = to_panel_simple(panel);
int num = 0;
+ /* add device node plane modes */
+ num += panel_simple_of_get_native_mode(p);
+
+ /* add hard-coded panel modes */
+ num += panel_simple_get_fixed_modes(p);
+
/* probe EDID if a DDC bus is available */
if (p->ddc) {
struct edid *edid = drm_get_edid(panel->connector, p->ddc);
}
}
- /* add hard-coded panel modes */
- num += panel_simple_get_fixed_modes(p);
-
return num;
}
struct panel_simple *p = to_panel_simple(panel);
unsigned int i;
+ if (!p->desc)
+ return 0;
+
if (p->desc->num_timings < num_timings)
num_timings = p->desc->num_timings;
{
struct device_node *backlight, *ddc;
struct panel_simple *panel;
+ struct panel_desc *of_desc;
+ u32 val;
int err;
panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
if (!panel)
return -ENOMEM;
+ if (!desc)
+ of_desc = devm_kzalloc(dev, sizeof(*of_desc), GFP_KERNEL);
+ else
+ of_desc = devm_kmemdup(dev, desc, sizeof(*of_desc), GFP_KERNEL);
+
+ if (!of_property_read_u32(dev->of_node, "bus-format", &val))
+ of_desc->bus_format = val;
+ if (!of_property_read_u32(dev->of_node, "delay,prepare", &val))
+ of_desc->delay.prepare = val;
+ if (!of_property_read_u32(dev->of_node, "delay,enable", &val))
+ of_desc->delay.enable = val;
+ if (!of_property_read_u32(dev->of_node, "delay,disable", &val))
+ of_desc->delay.disable = val;
+ if (!of_property_read_u32(dev->of_node, "delay,unprepare", &val))
+ of_desc->delay.unprepare = val;
+
panel->enabled = false;
panel->prepared = false;
- panel->desc = desc;
+ panel->desc = of_desc;
+ panel->dev = dev;
panel->supply = devm_regulator_get(dev, "power");
if (IS_ERR(panel->supply))
return PTR_ERR(panel->supply);
- panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
- GPIOD_OUT_LOW);
+ panel->enable_gpio = devm_gpiod_get_optional(dev, "enable", 0);
if (IS_ERR(panel->enable_gpio)) {
err = PTR_ERR(panel->enable_gpio);
dev_err(dev, "failed to request GPIO: %d\n", err);
},
};
+static const struct drm_display_mode auo_b101ew05_mode = {
+ .clock = 71000,
+ .hdisplay = 1280,
+ .hsync_start = 1280 + 18,
+ .hsync_end = 1280 + 18 + 10,
+ .htotal = 1280 + 18 + 10 + 100,
+ .vdisplay = 800,
+ .vsync_start = 800 + 6,
+ .vsync_end = 800 + 6 + 2,
+ .vtotal = 800 + 6 + 2 + 8,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc auo_b101ew05 = {
+ .modes = &auo_b101ew05_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 217,
+ .height = 136,
+ },
+};
+
static const struct drm_display_mode auo_b101xtn01_mode = {
.clock = 72000,
.hdisplay = 1366,
},
};
+static const struct drm_display_mode auo_b125han03_mode = {
+ .clock = 146900,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 48,
+ .hsync_end = 1920 + 48 + 32,
+ .htotal = 1920 + 48 + 32 + 140,
+ .vdisplay = 1080,
+ .vsync_start = 1080 + 2,
+ .vsync_end = 1080 + 2 + 5,
+ .vtotal = 1080 + 2 + 5 + 57,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc auo_b125han03 = {
+ .modes = &auo_b125han03_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 276,
+ .height = 156,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
static const struct drm_display_mode auo_b133xtn01_mode = {
.clock = 69500,
.hdisplay = 1366,
},
};
+static const struct drm_display_mode boe_nv125fhm_n73_mode = {
+ .clock = 72300,
+ .hdisplay = 1366,
+ .hsync_start = 1366 + 80,
+ .hsync_end = 1366 + 80 + 20,
+ .htotal = 1366 + 80 + 20 + 60,
+ .vdisplay = 768,
+ .vsync_start = 768 + 12,
+ .vsync_end = 768 + 12 + 2,
+ .vtotal = 768 + 12 + 2 + 8,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc boe_nv125fhm_n73 = {
+ .modes = &boe_nv125fhm_n73_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 276,
+ .height = 156,
+ },
+ .delay = {
+ .unprepare = 160,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
+static const struct drm_display_mode chunghwa_claa070wp03xg_mode = {
+ .clock = 67000,
+ .hdisplay = 800,
+ .hsync_start = 800 + 24,
+ .hsync_end = 800 + 24 + 16,
+ .htotal = 800 + 24 + 16 + 24,
+ .vdisplay = 1280,
+ .vsync_start = 1280 + 2,
+ .vsync_end = 1280 + 2 + 2,
+ .vtotal = 1280 + 2 + 2 + 4,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc chunghwa_claa070wp03xg = {
+ .modes = &chunghwa_claa070wp03xg_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 94,
+ .height = 151,
+ },
+};
+
static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
.clock = 72070,
.hdisplay = 1366,
},
};
+static const struct drm_display_mode innolux_n125hce_mode = {
+ .clock = 138780,
+ .hdisplay = 1920,
+ .hsync_start = 1920 + 80,
+ .hsync_end = 1920 + 80 + 30,
+ .htotal = 1920 + 80 + 30 + 50,
+ .vdisplay = 1080,
+ .vsync_start = 1080 + 12,
+ .vsync_end = 1080 + 12 + 4,
+ .vtotal = 1080 + 12 + 4 + 16,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
+};
+
+static const struct panel_desc innolux_n125hce = {
+ .modes = &innolux_n125hce_mode,
+ .num_modes = 1,
+ .bpc = 6,
+ .size = {
+ .width = 283,
+ .height = 168,
+ },
+ .delay = {
+ .unprepare = 600,
+ .enable = 100,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
static const struct drm_display_mode innolux_n156bge_l21_mode = {
.clock = 69300,
.hdisplay = 1366,
.bus_format = MEDIA_BUS_FMT_RGB888_1X7X4_SPWG,
};
+static const struct drm_display_mode sharp_lcd_f402_mode = {
+ .clock = 205000,
+ .hdisplay = 1536,
+ .hsync_start = 1536 + 12,
+ .hsync_end = 1536 + 12 + 48,
+ .htotal = 1536 + 12 + 48 + 16,
+ .vdisplay = 2048,
+ .vsync_start = 2048 + 8,
+ .vsync_end = 2048 + 8 + 8,
+ .vtotal = 2048 + 8 + 8 + 4,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc sharp_lcd_f402 = {
+ .modes = &sharp_lcd_f402_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 95,
+ .height = 54,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
+static const struct drm_display_mode lg_lp079qx1_sp0v_mode = {
+ .clock = 200000,
+ .hdisplay = 1536,
+ .hsync_start = 1536 + 12,
+ .hsync_end = 1536 + 12 + 16,
+ .htotal = 1536 + 12 + 16 + 48,
+ .vdisplay = 2048,
+ .vsync_start = 2048 + 8,
+ .vsync_end = 2048 + 8 + 4,
+ .vtotal = 2048 + 8 + 4 + 8,
+ .vrefresh = 60,
+ .flags = DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
+};
+
+static const struct panel_desc lg_lp079qx1_sp0v = {
+ .modes = &lg_lp079qx1_sp0v_mode,
+ .num_modes = 1,
+ .size = {
+ .width = 129,
+ .height = 171,
+ },
+ .bus_format = MEDIA_BUS_FMT_RGB666_1X18,
+};
+
static const struct drm_display_mode lg_lp097qx1_spa1_mode = {
.clock = 205210,
.hdisplay = 2048,
static const struct of_device_id platform_of_match[] = {
{
+ .compatible = "simple-panel",
+ .data = NULL,
+ }, {
.compatible = "ampire,am800480r3tmqwa1h",
.data = &ire_am800480r3tmqwa1h,
}, {
}, {
.compatible = "auo,b101ean01",
.data = &auo_b101ean01,
+ }, {
+ .compatible = "auo,b101ew05",
+ .data = &auo_b101ew05,
}, {
.compatible = "auo,b101xtn01",
.data = &auo_b101xtn01,
}, {
.compatible = "auo,b116xw03",
.data = &auo_b116xw03,
+ }, {
+ .compatible = "auo,b125han03",
+ .data = &auo_b125han03,
}, {
.compatible = "auo,b133htn01",
.data = &auo_b133htn01,
}, {
.compatible = "avic,tm070ddh03",
.data = &avic_tm070ddh03,
+ }, {
+ .compatible = "boe,nv125fhm-n73",
+ .data = &boe_nv125fhm_n73,
+ }, {
+ .compatible = "chunghwa,claa070wp03xg",
+ .data = &chunghwa_claa070wp03xg,
}, {
.compatible = "chunghwa,claa101wa01a",
.data = &chunghwa_claa101wa01a
}, {
.compatible = "innolux,n116bge",
.data = &innolux_n116bge,
+ }, {
+ .compatible = "innolux,n125hce",
+ .data = &innolux_n125hce,
}, {
.compatible = "innolux,n156bge-l21",
.data = &innolux_n156bge_l21,
}, {
.compatible = "lg,lb070wv8",
.data = &lg_lb070wv8,
+ }, {
+ .compatible = "lg,lp079qx1-sp0v",
+ .data = &lg_lp079qx1_sp0v,
}, {
.compatible = "lg,lp097qx1-spa1",
.data = &lg_lp097qx1_spa1,
}, {
.compatible = "samsung,ltn140at29-301",
.data = &samsung_ltn140at29_301,
+ }, {
+ .compatible = "sharp,lcd-f402",
+ .data = &sharp_lcd_f402,
}, {
.compatible = "shelly,sca07010-bfn-lnn",
.data = &shelly_sca07010_bfn_lnn,
static const struct of_device_id dsi_of_match[] = {
{
+ .compatible = "simple-panel-dsi",
+ .data = NULL
+ }, {
.compatible = "auo,b080uan01",
.data = &auo_b080uan01
}, {
{
const struct panel_desc_dsi *desc;
const struct of_device_id *id;
+ const struct panel_desc *pdesc;
+ u32 val;
int err;
id = of_match_node(dsi_of_match, dsi->dev.of_node);
desc = id->data;
- err = panel_simple_probe(&dsi->dev, &desc->desc);
+ if (desc) {
+ dsi->mode_flags = desc->flags;
+ dsi->format = desc->format;
+ dsi->lanes = desc->lanes;
+ pdesc = &desc->desc;
+ } else {
+ pdesc = NULL;
+ }
+
+ err = panel_simple_probe(&dsi->dev, pdesc);
if (err < 0)
return err;
- dsi->mode_flags = desc->flags;
- dsi->format = desc->format;
- dsi->lanes = desc->lanes;
+ if (!of_property_read_u32(dsi->dev.of_node, "dsi,flags", &val))
+ dsi->mode_flags = val;
+
+ if (!of_property_read_u32(dsi->dev.of_node, "dsi,format", &val))
+ dsi->format = val;
+
+ if (!of_property_read_u32(dsi->dev.of_node, "dsi,lanes", &val))
+ dsi->lanes = val;
return mipi_dsi_attach(dsi);
}