diff options
Diffstat (limited to 'drivers/gpu/drm/bridge/adv7511/adv7533.c')
-rw-r--r-- | drivers/gpu/drm/bridge/adv7511/adv7533.c | 110 |
1 files changed, 66 insertions, 44 deletions
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7533.c b/drivers/gpu/drm/bridge/adv7511/adv7533.c index aa19d5a40e31..27d63b804f31 100644 --- a/drivers/gpu/drm/bridge/adv7511/adv7533.c +++ b/drivers/gpu/drm/bridge/adv7511/adv7533.c @@ -26,10 +26,8 @@ static const struct reg_sequence adv7533_cec_fixed_registers[] = { static void adv7511_dsi_config_timing_gen(struct adv7511 *adv) { - struct mipi_dsi_device *dsi = adv->dsi; struct drm_display_mode *mode = &adv->curr_mode; unsigned int hsw, hfp, hbp, vsw, vfp, vbp; - u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ hsw = mode->hsync_end - mode->hsync_start; hfp = mode->hsync_start - mode->hdisplay; @@ -38,9 +36,10 @@ static void adv7511_dsi_config_timing_gen(struct adv7511 *adv) vfp = mode->vsync_start - mode->vdisplay; vbp = mode->vtotal - mode->vsync_end; - /* set pixel clock divider mode */ - regmap_write(adv->regmap_cec, 0x16, - clock_div_by_lanes[dsi->lanes - 2] << 3); + /* 03-01 Enable Internal Timing Generator */ + regmap_write(adv->regmap_cec, 0x27, 0xcb); + + /* 03-08 Timing Configuration */ /* horizontal porch params */ regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4); @@ -61,35 +60,66 @@ static void adv7511_dsi_config_timing_gen(struct adv7511 *adv) regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff); regmap_write(adv->regmap_cec, 0x36, vbp >> 4); regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff); + + /* 03-03 Reset Internal Timing Generator */ + regmap_write(adv->regmap_cec, 0x27, 0xcb); + regmap_write(adv->regmap_cec, 0x27, 0x8b); + regmap_write(adv->regmap_cec, 0x27, 0xcb); + } void adv7533_dsi_power_on(struct adv7511 *adv) { struct mipi_dsi_device *dsi = adv->dsi; + struct drm_display_mode *mode = &adv->curr_mode; + u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */ - if (adv->use_timing_gen) - adv7511_dsi_config_timing_gen(adv); + /* Gate DSI LP Oscillator */ + regmap_update_bits(adv->regmap_cec, 0x03, 0x02, 0x00); - /* set number of dsi lanes */ + /* 01-03 Initialisation (Fixed) Registers */ + regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers, + ARRAY_SIZE(adv7533_cec_fixed_registers)); + + /* 02-04 DSI Lanes */ regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4); - if (adv->use_timing_gen) { - /* reset internal timing generator */ - regmap_write(adv->regmap_cec, 0x27, 0xcb); - regmap_write(adv->regmap_cec, 0x27, 0x8b); - regmap_write(adv->regmap_cec, 0x27, 0xcb); - } else { - /* disable internal timing generator */ + /* 02-05 DSI Pixel Clock Divider */ + regmap_write(adv->regmap_cec, 0x16, + clock_div_by_lanes[dsi->lanes - 2] << 3); + + if (adv->use_timing_gen) + adv7511_dsi_config_timing_gen(adv); + else regmap_write(adv->regmap_cec, 0x27, 0x0b); - } - /* enable hdmi */ + /* 04-01 HDMI Output */ + regmap_write(adv->regmap, 0xaf, 0x16); + + /* 09-03 AVI Infoframe - RGB - 16-9 Aspect Ratio */ + regmap_write(adv->regmap, ADV7511_REG_AVI_INFOFRAME(0), 0x10); + if (FORMAT_RATIO(mode->hdisplay, mode->vdisplay) == RATIO_16_9) + regmap_write(adv->regmap, ADV7511_REG_AVI_INFOFRAME(1), 0x28); + else if (FORMAT_RATIO(mode->hdisplay, mode->vdisplay) == RATIO_4_3) + regmap_write(adv->regmap, ADV7511_REG_AVI_INFOFRAME(1), 0x18); + + /* 04-04 GC Packet Enable */ + regmap_write(adv->regmap, ADV7511_REG_PACKET_ENABLE0, 0x80); + + /* 04-06 GC Colour Depth - 24 Bit */ + regmap_write(adv->regmap, 0x4c, 0x04); + + /* 04-09 Down Dither Output Colour Depth - 8 Bit (default) */ + regmap_write(adv->regmap, 0x49, 0x00); + + /* 07-01 CEC Power Mode - Always Active */ + regmap_write(adv->regmap_cec, 0xbe, 0x3d); + + /* 04-03 HDMI Output Enable */ regmap_write(adv->regmap_cec, 0x03, 0x89); /* disable test mode */ regmap_write(adv->regmap_cec, 0x55, 0x00); - regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers, - ARRAY_SIZE(adv7533_cec_fixed_registers)); } void adv7533_dsi_power_off(struct adv7511 *adv) @@ -100,28 +130,6 @@ void adv7533_dsi_power_off(struct adv7511 *adv) regmap_write(adv->regmap_cec, 0x27, 0x0b); } -void adv7533_mode_set(struct adv7511 *adv, const struct drm_display_mode *mode) -{ - struct mipi_dsi_device *dsi = adv->dsi; - int lanes, ret; - - if (adv->num_dsi_lanes != 4) - return; - - if (mode->clock > 80000) - lanes = 4; - else - lanes = 3; - - if (lanes != dsi->lanes) { - mipi_dsi_detach(dsi); - dsi->lanes = lanes; - ret = mipi_dsi_attach(dsi); - if (ret) - dev_err(&dsi->dev, "failed to change host lanes\n"); - } -} - int adv7533_patch_registers(struct adv7511 *adv) { return regmap_register_patch(adv->regmap, @@ -143,7 +151,7 @@ int adv7533_attach_dsi(struct adv7511 *adv) struct mipi_dsi_device *dsi; int ret = 0; const struct mipi_dsi_device_info info = { .type = "adv7533", - .channel = 0, + .channel = adv->channel_id, .node = NULL, }; @@ -189,14 +197,24 @@ void adv7533_detach_dsi(struct adv7511 *adv) int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) { - u32 num_lanes; + struct device *dev = &adv->i2c_main->dev; + u32 num_lanes = 0, channel_id = 0; + of_property_read_u32(np, "adi,dsi-channel", &channel_id); of_property_read_u32(np, "adi,dsi-lanes", &num_lanes); - if (num_lanes < 1 || num_lanes > 4) + if (num_lanes < 1 || num_lanes > 4) { + dev_err(dev, "Invalid dsi-lanes: %d\n", num_lanes); return -EINVAL; + } + + if (channel_id > 3) { + dev_err(dev, "Invalid dsi-channel: %d\n", channel_id); + return -EINVAL; + } adv->num_dsi_lanes = num_lanes; + adv->channel_id = channel_id; adv->host_node = of_graph_get_remote_node(np, 0, 0); if (!adv->host_node) @@ -207,6 +225,10 @@ int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv) adv->use_timing_gen = !of_property_read_bool(np, "adi,disable-timing-generator"); + of_property_read_u32(np, "adi,addr-cec", &adv->addr_cec); + of_property_read_u32(np, "adi,addr-edid", &adv->addr_edid); + of_property_read_u32(np, "adi,addr-pkt", &adv->addr_pkt); + /* TODO: Check if these need to be parsed by DT or not */ adv->rgb = true; adv->embedded_sync = false; |