diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 107 |
1 files changed, 82 insertions, 25 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index cd7f1e499616..9336006b475d 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -15,6 +15,10 @@ #include "drm.h" #include "gem.h" +struct tegra_dc_soc_info { + bool supports_interlacing; +}; + struct tegra_plane { struct drm_plane base; unsigned int index; @@ -658,19 +662,12 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc, /* program display mode */ tegra_dc_set_timings(dc, mode); - value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; - tegra_dc_writel(dc, value, DC_DISP_DATA_ENABLE_OPTIONS); - - value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1)); - value &= ~LVS_OUTPUT_POLARITY_LOW; - value &= ~LHS_OUTPUT_POLARITY_LOW; - tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); - - value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB | - DISP_ORDER_RED_BLUE; - tegra_dc_writel(dc, value, DC_DISP_DISP_INTERFACE_CONTROL); - - tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS); + /* interlacing isn't supported yet, so disable it */ + if (dc->soc->supports_interlacing) { + value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL); + value &= ~INTERLACE_ENABLE; + tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL); + } value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); @@ -735,10 +732,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc) PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); - value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); - value |= DISP_CTRL_MODE_C_DISPLAY; - tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); - /* initialize timer */ value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); @@ -1107,8 +1100,6 @@ static int tegra_dc_init(struct host1x_client *client) struct tegra_dc *dc = host1x_client_to_dc(client); int err; - dc->pipe = tegra->drm->mode_config.num_crtc; - drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs); drm_mode_crtc_set_gamma_size(&dc->base, 256); drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); @@ -1167,8 +1158,71 @@ static const struct host1x_client_ops dc_client_ops = { .exit = tegra_dc_exit, }; +static const struct tegra_dc_soc_info tegra20_dc_soc_info = { + .supports_interlacing = false, +}; + +static const struct tegra_dc_soc_info tegra30_dc_soc_info = { + .supports_interlacing = false, +}; + +static const struct tegra_dc_soc_info tegra124_dc_soc_info = { + .supports_interlacing = true, +}; + +static const struct of_device_id tegra_dc_of_match[] = { + { + .compatible = "nvidia,tegra124-dc", + .data = &tegra124_dc_soc_info, + }, { + .compatible = "nvidia,tegra30-dc", + .data = &tegra30_dc_soc_info, + }, { + .compatible = "nvidia,tegra20-dc", + .data = &tegra20_dc_soc_info, + }, { + /* sentinel */ + } +}; + +static int tegra_dc_parse_dt(struct tegra_dc *dc) +{ + struct device_node *np; + u32 value = 0; + int err; + + err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value); + if (err < 0) { + dev_err(dc->dev, "missing \"nvidia,head\" property\n"); + + /* + * If the nvidia,head property isn't present, try to find the + * correct head number by looking up the position of this + * display controller's node within the device tree. Assuming + * that the nodes are ordered properly in the DTS file and + * that the translation into a flattened device tree blob + * preserves that ordering this will actually yield the right + * head number. + * + * If those assumptions don't hold, this will still work for + * cases where only a single display controller is used. + */ + for_each_matching_node(np, tegra_dc_of_match) { + if (np == dc->dev->of_node) + break; + + value++; + } + } + + dc->pipe = value; + + return 0; +} + static int tegra_dc_probe(struct platform_device *pdev) { + const struct of_device_id *id; struct resource *regs; struct tegra_dc *dc; int err; @@ -1177,9 +1231,18 @@ static int tegra_dc_probe(struct platform_device *pdev) if (!dc) return -ENOMEM; + id = of_match_node(tegra_dc_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + spin_lock_init(&dc->lock); INIT_LIST_HEAD(&dc->list); dc->dev = &pdev->dev; + dc->soc = id->data; + + err = tegra_dc_parse_dt(dc); + if (err < 0) + return err; dc->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dc->clk)) { @@ -1253,12 +1316,6 @@ static int tegra_dc_remove(struct platform_device *pdev) return 0; } -static struct of_device_id tegra_dc_of_match[] = { - { .compatible = "nvidia,tegra30-dc", }, - { .compatible = "nvidia,tegra20-dc", }, - { }, -}; - struct platform_driver tegra_dc_driver = { .driver = { .name = "tegra-dc", |