Heavily based on the Armada 510 (Dove) support. Tested to work well with Display 1 and Display 2 clocks driving the internal panel on the OLPC XO 1.75 laptop. Some tweaking might be required if anyone wants to use it with a MIPI or HDMI encoder. The data sheet is not available, but James Cameron of OLPC kindly provided some details about the LCD_SCLK_DIV register. Link: https://lists.freedesktop.org/archives/dri-devel/2018-December/201021.html Signed-off-by: Lubomir Rintel <lkundrak@xxxxx> --- Applies on top of "drm-armada-devel" branch of git://git.armlinux.org.uk/~rmk/linux-arm.git Changes since v1: - Aligned with more recent Armada 510 support: using the same clock names and allowing for more flexible pixel clock source selection. drivers/gpu/drm/armada/Makefile | 1 + drivers/gpu/drm/armada/armada_610.c | 143 +++++++++++++++++++++++++++ drivers/gpu/drm/armada/armada_crtc.c | 4 + drivers/gpu/drm/armada/armada_drm.h | 1 + drivers/gpu/drm/armada/armada_hw.h | 10 ++ 5 files changed, 159 insertions(+) create mode 100644 drivers/gpu/drm/armada/armada_610.c diff --git a/drivers/gpu/drm/armada/Makefile b/drivers/gpu/drm/armada/Makefile index 9bc3c3213724..5bbf86324cda 100644 --- a/drivers/gpu/drm/armada/Makefile +++ b/drivers/gpu/drm/armada/Makefile @@ -2,6 +2,7 @@ armada-y := armada_crtc.o armada_drv.o armada_fb.o armada_fbdev.o \ armada_gem.o armada_overlay.o armada_plane.o armada_trace.o armada-y += armada_510.o +armada-y += armada_610.o armada-$(CONFIG_DEBUG_FS) += armada_debugfs.o obj-$(CONFIG_DRM_ARMADA) := armada.o diff --git a/drivers/gpu/drm/armada/armada_610.c b/drivers/gpu/drm/armada/armada_610.c new file mode 100644 index 000000000000..586965fca907 --- /dev/null +++ b/drivers/gpu/drm/armada/armada_610.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2012 Russell King + * Copyright (C) 2018,2019 Lubomir Rintel + * Largely based on Armada 510 support + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Armada MMP2 variant support + */ +#include <linux/clk.h> +#include <drm/drm_modes.h> +#include <drm/drm_crtc.h> +#include "armada_crtc.h" +#include "armada_drm.h" +#include "armada_hw.h" + +struct armada610_variant_data { + struct clk *clks[4]; + struct clk *sel_clk; +}; + +static int armada610_crtc_init(struct armada_crtc *dcrtc, struct device *dev) +{ + struct armada610_variant_data *v; + struct property *prop; + struct clk *clk; + const char *s; + int idx; + + v = devm_kzalloc(dev, sizeof(*v), GFP_KERNEL); + if (!v) + return -ENOMEM; + + dcrtc->variant_data = v; + + of_property_for_each_string(dev->of_node, "clock-names", prop, s) { + if (!strcmp(s, "ext_ref_clk0")) + idx = 0; + else if (!strcmp(s, "ext_ref_clk1")) + idx = 1; + else if (!strcmp(s, "plldivider")) + idx = 2; + else if (!strcmp(s, "axibus")) + idx = 3; + else + continue; + + clk = devm_clk_get(dev, s); + if (IS_ERR(clk)) + return PTR_ERR(clk) == -ENOENT ? -EPROBE_DEFER : + PTR_ERR(clk); + v->clks[idx] = clk; + } + + return 0; +} + +static const u32 armada610_clk_sels[] = { + SCLK_610_DISP0, + SCLK_610_DISP1, + SCLK_610_PLL, + SCLK_610_AXI, +}; + +static const struct armada_clocking_params armada610_clocking = { + /* HDMI requires -0.6%..+0.5% */ + .permillage_min = 0, + .permillage_max = 2000, + .settable = BIT(0) | BIT(1), + .div_max = SCLK_610_INT_DIV_MASK, +}; + +/* + * This gets called with sclk = NULL to test whether the mode is + * supportable, and again with sclk != NULL to set the clocks up for + * that. The former can return an error, but the latter is expected + * not to. + */ +static int armada610_crtc_compute_clock(struct armada_crtc *dcrtc, + const struct drm_display_mode *mode, uint32_t *sclk) +{ + struct armada610_variant_data *v = dcrtc->variant_data; + unsigned long desired_khz = mode->crtc_clock; + struct armada_clk_result res; + int ret, idx; + + idx = armada_crtc_select_clock(dcrtc, &res, &armada610_clocking, + v->clks, ARRAY_SIZE(v->clks), + desired_khz); + if (idx < 0) + return idx; + + ret = clk_prepare_enable(res.clk); + if (ret) + return ret; + + if (sclk) { + clk_set_rate(res.clk, res.desired_clk_hz); + + *sclk = 0x00001000; /* No idea */ + *sclk |= 1 << 8; /* MIPI clock bypass */ + *sclk |= armada610_clk_sels[idx]; + *sclk |= res.div; + + /* We are now using this clock */ + v->sel_clk = res.clk; + swap(dcrtc->clk, res.clk); + } + + clk_disable_unprepare(res.clk); + + return 0; +} + +static void armada610_crtc_disable(struct armada_crtc *dcrtc) +{ + if (dcrtc->clk) { + clk_disable_unprepare(dcrtc->clk); + dcrtc->clk = NULL; + } +} + +static void armada610_crtc_enable(struct armada_crtc *dcrtc, + const struct drm_display_mode *mode) +{ + struct armada610_variant_data *v = dcrtc->variant_data; + + if (!dcrtc->clk && v->sel_clk) { + if (!WARN_ON(clk_prepare_enable(v->sel_clk))) + dcrtc->clk = v->sel_clk; + } +} + + +const struct armada_variant armada610_ops = { + .init = armada610_crtc_init, + .compute_clock = armada610_crtc_compute_clock, + .disable = armada610_crtc_disable, + .enable = armada610_crtc_enable, +}; diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c index 047136fda14b..d5cf35f6dab1 100644 --- a/drivers/gpu/drm/armada/armada_crtc.c +++ b/drivers/gpu/drm/armada/armada_crtc.c @@ -1104,6 +1104,10 @@ static const struct of_device_id armada_lcd_of_match[] = { .compatible = "marvell,dove-lcd", .data = &armada510_ops, }, + { + .compatible = "marvell,mmp2-lcd", + .data = &armada610_ops, + }, {} }; MODULE_DEVICE_TABLE(of, armada_lcd_of_match); diff --git a/drivers/gpu/drm/armada/armada_drm.h b/drivers/gpu/drm/armada/armada_drm.h index b6307235f320..03aeb9c030e4 100644 --- a/drivers/gpu/drm/armada/armada_drm.h +++ b/drivers/gpu/drm/armada/armada_drm.h @@ -52,6 +52,7 @@ struct armada_variant { /* Variant ops */ extern const struct armada_variant armada510_ops; +extern const struct armada_variant armada610_ops; struct armada_private { struct drm_device drm; diff --git a/drivers/gpu/drm/armada/armada_hw.h b/drivers/gpu/drm/armada/armada_hw.h index 5b1af0cc9f50..19544dfd6afb 100644 --- a/drivers/gpu/drm/armada/armada_hw.h +++ b/drivers/gpu/drm/armada/armada_hw.h @@ -219,6 +219,16 @@ enum { SCLK_510_FRAC_DIV_MASK = 0xfff << 16, SCLK_510_INT_DIV_MASK = 0xffff << 0, + /* Armada 610 */ + SCLK_610_AXI = 0x0 << 30, + SCLK_610_DISP0 = 0x1 << 30, /* LCD Display 1 */ + SCLK_610_DISP1 = 0x2 << 30, /* LCD Display 2 */ + SCLK_610_PLL = 0x3 << 30, /* HDMI PLL clock */ + SCLK_610_PANEL_CLK_DIS = 0x1 << 28, /* 1 = panel clock disabled */ + SCLK_610_FRAC_DIV_MASK = 0xfff << 16, + SCLK_610_MIPI_DIV_MASK = 0xf << 8, /* 0 = off, 1 = bypass, ... */ + SCLK_610_INT_DIV_MASK = 0xff << 0, + /* Armada 16x */ SCLK_16X_AHB = 0x0 << 28, SCLK_16X_PCLK = 0x1 << 28, -- 2.20.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel