2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-15 08:44:14 +08:00

Merge branch 'drm/next/du' of git://linuxtv.org/pinchartl/media into drm-next

rcar-du -next branch.

* 'drm/next/du' of git://linuxtv.org/pinchartl/media:
  drm: rcar-du: Fix LVDS start sequence on Gen3
  drm: rcar-du: Fix H/V sync signal polarity configuration
  drm: rcar-du: Fix display timing controller parameter
  drm: rcar-du: Fix dot clock routing configuration
  drm: rcar-du: Add R8A7796 support
  drm: rcar-du: Add R8A7792 support
  drm: rcar-du: Simplify and fix probe error handling
  drm: rcar-du: Fix crash in encoder failure error path
  drm: rcar-du: Remove memory allocation error message
  drm: rcar-du: Remove test for impossible error condition
  drm: rcar-du: Bring HDMI encoder comments in line with the driver
  drm: rcar-du: Constify node argument to rcar_du_lvds_connector_init()
  video: of: Constify node argument to display timing functions
This commit is contained in:
Dave Airlie 2016-11-16 09:39:21 +10:00
commit 1a3865d64a
11 changed files with 117 additions and 71 deletions

View File

@ -6,9 +6,11 @@ Required Properties:
- "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU - "renesas,du-r8a7779" for R8A7779 (R-Car H1) compatible DU
- "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU - "renesas,du-r8a7790" for R8A7790 (R-Car H2) compatible DU
- "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU - "renesas,du-r8a7791" for R8A7791 (R-Car M2-W) compatible DU
- "renesas,du-r8a7792" for R8A7792 (R-Car V2H) compatible DU
- "renesas,du-r8a7793" for R8A7793 (R-Car M2-N) compatible DU - "renesas,du-r8a7793" for R8A7793 (R-Car M2-N) compatible DU
- "renesas,du-r8a7794" for R8A7794 (R-Car E2) compatible DU - "renesas,du-r8a7794" for R8A7794 (R-Car E2) compatible DU
- "renesas,du-r8a7795" for R8A7795 (R-Car H3) compatible DU - "renesas,du-r8a7795" for R8A7795 (R-Car H3) compatible DU
- "renesas,du-r8a7796" for R8A7796 (R-Car M3-W) compatible DU
- reg: A list of base address and length of each memory resource, one for - reg: A list of base address and length of each memory resource, one for
each entry in the reg-names property. each entry in the reg-names property.
@ -25,10 +27,10 @@ Required Properties:
- clock-names: Name of the clocks. This property is model-dependent. - clock-names: Name of the clocks. This property is model-dependent.
- R8A7779 uses a single functional clock. The clock doesn't need to be - R8A7779 uses a single functional clock. The clock doesn't need to be
named. named.
- R8A779[01345] use one functional clock per channel and one clock per LVDS - R8A779[0123456] use one functional clock per channel and one clock per
encoder (if available). The functional clocks must be named "du.x" with LVDS encoder (if available). The functional clocks must be named "du.x"
"x" being the channel numerical index. The LVDS clocks must be named with "x" being the channel numerical index. The LVDS clocks must be
"lvds.x" with "x" being the LVDS encoder numerical index. named "lvds.x" with "x" being the LVDS encoder numerical index.
- In addition to the functional and encoder clocks, all DU versions also - In addition to the functional and encoder clocks, all DU versions also
support externally supplied pixel clocks. Those clocks are optional. support externally supplied pixel clocks. Those clocks are optional.
When supplied they must be named "dclkin.x" with "x" being the input When supplied they must be named "dclkin.x" with "x" being the input
@ -47,9 +49,11 @@ corresponding to each DU output.
R8A7779 (H1) DPAD 0 DPAD 1 - - R8A7779 (H1) DPAD 0 DPAD 1 - -
R8A7790 (H2) DPAD LVDS 0 LVDS 1 - R8A7790 (H2) DPAD LVDS 0 LVDS 1 -
R8A7791 (M2-W) DPAD LVDS 0 - - R8A7791 (M2-W) DPAD LVDS 0 - -
R8A7792 (V2H) DPAD 0 DPAD 1 - -
R8A7793 (M2-N) DPAD LVDS 0 - - R8A7793 (M2-N) DPAD LVDS 0 - -
R8A7794 (E2) DPAD 0 DPAD 1 - - R8A7794 (E2) DPAD 0 DPAD 1 - -
R8A7795 (H3) DPAD HDMI 0 HDMI 1 LVDS R8A7795 (H3) DPAD HDMI 0 HDMI 1 LVDS
R8A7796 (M3-W) DPAD HDMI LVDS -
Example: R8A7790 (R-Car H2) DU Example: R8A7790 (R-Car H2) DU

View File

@ -149,8 +149,8 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
/* Signal polarities */ /* Signal polarities */
value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? DSMR_VSL : 0)
| ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL) | ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? DSMR_HSL : 0)
| DSMR_DIPM_DISP | DSMR_CSPM; | DSMR_DIPM_DISP | DSMR_CSPM;
rcar_du_crtc_write(rcrtc, DSMR, value); rcar_du_crtc_write(rcrtc, DSMR, value);
@ -172,7 +172,7 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
mode->crtc_vsync_start - 1); mode->crtc_vsync_start - 1);
rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1); rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1);
rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start); rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start - 1);
rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
} }

View File

@ -110,6 +110,27 @@ static const struct rcar_du_device_info rcar_du_r8a7791_info = {
.num_lvds = 1, .num_lvds = 1,
}; };
static const struct rcar_du_device_info rcar_du_r8a7792_info = {
.gen = 2,
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
| RCAR_DU_FEATURE_EXT_CTRL_REGS,
.num_crtcs = 2,
.routes = {
/* R8A7792 has two RGB outputs. */
[RCAR_DU_OUTPUT_DPAD0] = {
.possible_crtcs = BIT(0),
.encoder_type = DRM_MODE_ENCODER_NONE,
.port = 0,
},
[RCAR_DU_OUTPUT_DPAD1] = {
.possible_crtcs = BIT(1),
.encoder_type = DRM_MODE_ENCODER_NONE,
.port = 1,
},
},
.num_lvds = 0,
};
static const struct rcar_du_device_info rcar_du_r8a7794_info = { static const struct rcar_du_device_info rcar_du_r8a7794_info = {
.gen = 2, .gen = 2,
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
@ -157,13 +178,39 @@ static const struct rcar_du_device_info rcar_du_r8a7795_info = {
.num_lvds = 1, .num_lvds = 1,
}; };
static const struct rcar_du_device_info rcar_du_r8a7796_info = {
.gen = 3,
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
| RCAR_DU_FEATURE_EXT_CTRL_REGS
| RCAR_DU_FEATURE_VSP1_SOURCE,
.num_crtcs = 3,
.routes = {
/* R8A7796 has one RGB output, one LVDS output and one
* (currently unsupported) HDMI output.
*/
[RCAR_DU_OUTPUT_DPAD0] = {
.possible_crtcs = BIT(2),
.encoder_type = DRM_MODE_ENCODER_NONE,
.port = 0,
},
[RCAR_DU_OUTPUT_LVDS0] = {
.possible_crtcs = BIT(0),
.encoder_type = DRM_MODE_ENCODER_LVDS,
.port = 2,
},
},
.num_lvds = 1,
};
static const struct of_device_id rcar_du_of_table[] = { static const struct of_device_id rcar_du_of_table[] = {
{ .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info }, { .compatible = "renesas,du-r8a7779", .data = &rcar_du_r8a7779_info },
{ .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info }, { .compatible = "renesas,du-r8a7790", .data = &rcar_du_r8a7790_info },
{ .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info }, { .compatible = "renesas,du-r8a7791", .data = &rcar_du_r8a7791_info },
{ .compatible = "renesas,du-r8a7792", .data = &rcar_du_r8a7792_info },
{ .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info }, { .compatible = "renesas,du-r8a7793", .data = &rcar_du_r8a7791_info },
{ .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info }, { .compatible = "renesas,du-r8a7794", .data = &rcar_du_r8a7794_info },
{ .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info }, { .compatible = "renesas,du-r8a7795", .data = &rcar_du_r8a7795_info },
{ .compatible = "renesas,du-r8a7796", .data = &rcar_du_r8a7796_info },
{ } { }
}; };
@ -283,7 +330,6 @@ static int rcar_du_remove(struct platform_device *pdev)
drm_kms_helper_poll_fini(ddev); drm_kms_helper_poll_fini(ddev);
drm_mode_config_cleanup(ddev); drm_mode_config_cleanup(ddev);
drm_vblank_cleanup(ddev);
drm_dev_unref(ddev); drm_dev_unref(ddev);
@ -292,18 +338,12 @@ static int rcar_du_remove(struct platform_device *pdev)
static int rcar_du_probe(struct platform_device *pdev) static int rcar_du_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node;
struct rcar_du_device *rcdu; struct rcar_du_device *rcdu;
struct drm_device *ddev; struct drm_device *ddev;
struct resource *mem; struct resource *mem;
int ret; int ret;
if (np == NULL) { /* Allocate and initialize the R-Car device structure. */
dev_err(&pdev->dev, "no device tree node\n");
return -ENODEV;
}
/* Allocate and initialize the DRM and R-Car device structures. */
rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL); rcdu = devm_kzalloc(&pdev->dev, sizeof(*rcdu), GFP_KERNEL);
if (rcdu == NULL) if (rcdu == NULL)
return -ENOMEM; return -ENOMEM;
@ -313,6 +353,15 @@ static int rcar_du_probe(struct platform_device *pdev)
rcdu->dev = &pdev->dev; rcdu->dev = &pdev->dev;
rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data; rcdu->info = of_match_device(rcar_du_of_table, rcdu->dev)->data;
platform_set_drvdata(pdev, rcdu);
/* I/O resources */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(rcdu->mmio))
return PTR_ERR(rcdu->mmio);
/* DRM/KMS objects */
ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev); ddev = drm_dev_alloc(&rcar_du_driver, &pdev->dev);
if (IS_ERR(ddev)) if (IS_ERR(ddev))
return PTR_ERR(ddev); return PTR_ERR(ddev);
@ -320,24 +369,6 @@ static int rcar_du_probe(struct platform_device *pdev)
rcdu->ddev = ddev; rcdu->ddev = ddev;
ddev->dev_private = rcdu; ddev->dev_private = rcdu;
platform_set_drvdata(pdev, rcdu);
/* I/O resources */
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
rcdu->mmio = devm_ioremap_resource(&pdev->dev, mem);
if (IS_ERR(rcdu->mmio)) {
ret = PTR_ERR(rcdu->mmio);
goto error;
}
/* Initialize vertical blanking interrupts handling. Start with vblank
* disabled for all CRTCs.
*/
ret = drm_vblank_init(ddev, (1 << rcdu->info->num_crtcs) - 1);
if (ret < 0)
goto error;
/* DRM/KMS objects */
ret = rcar_du_modeset_init(rcdu); ret = rcar_du_modeset_init(rcdu);
if (ret < 0) { if (ret < 0) {
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)

View File

@ -105,16 +105,20 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) { if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
rcar_du_group_setup_defr8(rgrp); rcar_du_group_setup_defr8(rgrp);
/* Configure input dot clock routing. We currently hardcode the /*
* configuration to routing DOTCLKINn to DUn. * Configure input dot clock routing. We currently hardcode the
* configuration to routing DOTCLKINn to DUn. Register fields
* depend on the DU generation, but the resulting value is 0 in
* all cases.
*
* On Gen2 a single register in the first group controls dot
* clock selection for all channels, while on Gen3 dot clocks
* are setup through per-group registers, only available when
* the group has two channels.
*/ */
rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE | if ((rcdu->info->gen < 3 && rgrp->index == 0) ||
DIDSR_LCDS_DCLKIN(2) | (rcdu->info->gen == 3 && rgrp->num_crtcs > 1))
DIDSR_LCDS_DCLKIN(1) | rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE);
DIDSR_LCDS_DCLKIN(0) |
DIDSR_PDCS_CLK(2, 0) |
DIDSR_PDCS_CLK(1, 0) |
DIDSR_PDCS_CLK(0, 0));
} }
if (rcdu->info->gen >= 3) if (rcdu->info->gen >= 3)

View File

@ -108,7 +108,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
if (hdmienc == NULL) if (hdmienc == NULL)
return -ENOMEM; return -ENOMEM;
/* Locate drm bridge from the hdmi encoder DT node */ /* Locate the DRM bridge from the HDMI encoder DT node. */
bridge = of_drm_find_bridge(np); bridge = of_drm_find_bridge(np);
if (!bridge) if (!bridge)
return -EPROBE_DEFER; return -EPROBE_DEFER;
@ -123,7 +123,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
renc->hdmi = hdmienc; renc->hdmi = hdmienc;
hdmienc->renc = renc; hdmienc->renc = renc;
/* Link drm_bridge to encoder */ /* Link the bridge to the encoder. */
bridge->encoder = encoder; bridge->encoder = encoder;
encoder->bridge = bridge; encoder->bridge = bridge;

View File

@ -454,13 +454,13 @@ static int rcar_du_encoders_init_one(struct rcar_du_device *rcdu,
} }
ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector); ret = rcar_du_encoder_init(rcdu, enc_type, output, encoder, connector);
of_node_put(encoder);
of_node_put(connector);
if (ret && ret != -EPROBE_DEFER) if (ret && ret != -EPROBE_DEFER)
dev_warn(rcdu->dev, dev_warn(rcdu->dev,
"failed to initialize encoder %s (%d), skipping\n", "failed to initialize encoder %s on output %u (%d), skipping\n",
encoder->full_name, ret); of_node_full_name(encoder), output, ret);
of_node_put(encoder);
of_node_put(connector);
return ret; return ret;
} }
@ -568,6 +568,13 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
if (ret < 0) if (ret < 0)
return ret; return ret;
/* Initialize vertical blanking interrupts handling. Start with vblank
* disabled for all CRTCs.
*/
ret = drm_vblank_init(dev, (1 << rcdu->info->num_crtcs) - 1);
if (ret < 0)
return ret;
/* Initialize the groups. */ /* Initialize the groups. */
num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2); num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);

View File

@ -79,7 +79,7 @@ static const struct drm_connector_funcs connector_funcs = {
int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
struct rcar_du_encoder *renc, struct rcar_du_encoder *renc,
/* TODO const */ struct device_node *np) const struct device_node *np)
{ {
struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc);
struct rcar_du_lvds_connector *lvdscon; struct rcar_du_lvds_connector *lvdscon;

View File

@ -19,6 +19,6 @@ struct rcar_du_encoder;
int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu, int rcar_du_lvds_connector_init(struct rcar_du_device *rcdu,
struct rcar_du_encoder *renc, struct rcar_du_encoder *renc,
struct device_node *np); const struct device_node *np);
#endif /* __RCAR_DU_LVDSCON_H__ */ #endif /* __RCAR_DU_LVDSCON_H__ */

View File

@ -104,7 +104,14 @@ static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
rcar_lvds_write(lvds, LVDPLLCR, pllcr); rcar_lvds_write(lvds, LVDPLLCR, pllcr);
/* Turn the PLL on, set it to LVDS normal mode, wait for the startup /* Turn all the channels on. */
rcar_lvds_write(lvds, LVDCR1,
LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
LVDCR1_CLKSTBY_GEN3);
/*
* Turn the PLL on, set it to LVDS normal mode, wait for the startup
* delay and turn the output on. * delay and turn the output on.
*/ */
lvdcr0 = LVDCR0_PLLON; lvdcr0 = LVDCR0_PLLON;
@ -117,12 +124,6 @@ static void rcar_du_lvdsenc_start_gen3(struct rcar_du_lvdsenc *lvds,
lvdcr0 |= LVDCR0_LVRES; lvdcr0 |= LVDCR0_LVRES;
rcar_lvds_write(lvds, LVDCR0, lvdcr0); rcar_lvds_write(lvds, LVDCR0, lvdcr0);
/* Turn all the channels on. */
rcar_lvds_write(lvds, LVDCR1,
LVDCR1_CHSTBY_GEN3(3) | LVDCR1_CHSTBY_GEN3(2) |
LVDCR1_CHSTBY_GEN3(1) | LVDCR1_CHSTBY_GEN3(0) |
LVDCR1_CLKSTBY_GEN3);
} }
static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds, static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
@ -241,10 +242,8 @@ int rcar_du_lvdsenc_init(struct rcar_du_device *rcdu)
for (i = 0; i < rcdu->info->num_lvds; ++i) { for (i = 0; i < rcdu->info->num_lvds; ++i) {
lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL); lvds = devm_kzalloc(&pdev->dev, sizeof(*lvds), GFP_KERNEL);
if (lvds == NULL) { if (lvds == NULL)
dev_err(&pdev->dev, "failed to allocate private data\n");
return -ENOMEM; return -ENOMEM;
}
lvds->dev = rcdu; lvds->dev = rcdu;
lvds->index = i; lvds->index = i;

View File

@ -119,7 +119,7 @@ static int of_parse_display_timing(const struct device_node *np,
* @name: name of the timing node * @name: name of the timing node
* @dt: display_timing struct to fill * @dt: display_timing struct to fill
**/ **/
int of_get_display_timing(struct device_node *np, const char *name, int of_get_display_timing(const struct device_node *np, const char *name,
struct display_timing *dt) struct display_timing *dt)
{ {
struct device_node *timing_np; struct device_node *timing_np;
@ -142,7 +142,7 @@ EXPORT_SYMBOL_GPL(of_get_display_timing);
* of_get_display_timings - parse all display_timing entries from a device_node * of_get_display_timings - parse all display_timing entries from a device_node
* @np: device_node with the subnodes * @np: device_node with the subnodes
**/ **/
struct display_timings *of_get_display_timings(struct device_node *np) struct display_timings *of_get_display_timings(const struct device_node *np)
{ {
struct device_node *timings_np; struct device_node *timings_np;
struct device_node *entry; struct device_node *entry;
@ -258,7 +258,7 @@ EXPORT_SYMBOL_GPL(of_get_display_timings);
* of_display_timings_exist - check if a display-timings node is provided * of_display_timings_exist - check if a display-timings node is provided
* @np: device_node with the timing * @np: device_node with the timing
**/ **/
int of_display_timings_exist(struct device_node *np) int of_display_timings_exist(const struct device_node *np)
{ {
struct device_node *timings_np; struct device_node *timings_np;

View File

@ -16,21 +16,22 @@ struct display_timings;
#define OF_USE_NATIVE_MODE -1 #define OF_USE_NATIVE_MODE -1
#ifdef CONFIG_OF #ifdef CONFIG_OF
int of_get_display_timing(struct device_node *np, const char *name, int of_get_display_timing(const struct device_node *np, const char *name,
struct display_timing *dt); struct display_timing *dt);
struct display_timings *of_get_display_timings(struct device_node *np); struct display_timings *of_get_display_timings(const struct device_node *np);
int of_display_timings_exist(struct device_node *np); int of_display_timings_exist(const struct device_node *np);
#else #else
static inline int of_get_display_timing(struct device_node *np, const char *name, static inline int of_get_display_timing(const struct device_node *np,
struct display_timing *dt) const char *name, struct display_timing *dt)
{ {
return -ENOSYS; return -ENOSYS;
} }
static inline struct display_timings *of_get_display_timings(struct device_node *np) static inline struct display_timings *
of_get_display_timings(const struct device_node *np)
{ {
return NULL; return NULL;
} }
static inline int of_display_timings_exist(struct device_node *np) static inline int of_display_timings_exist(const struct device_node *np)
{ {
return -ENOSYS; return -ENOSYS;
} }