From 80a58240efef576ef909f7d99180ae2a70ca68a5 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 21 Apr 2017 16:38:50 +0800 Subject: drm/sun4i: Use lists to track registered display backends and TCONs To support multiple display pipelines, we need to keep track of the multiple display backends and TCONs registered with the driver. Switch to lists to track registered components. Components are only appended to their respective lists if the bind process was successful. The TCON bind function now defers if a backend was not registered. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 6 +++++- drivers/gpu/drm/sun4i/sun4i_backend.h | 4 ++++ drivers/gpu/drm/sun4i/sun4i_drv.c | 2 ++ drivers/gpu/drm/sun4i/sun4i_drv.h | 5 +++-- drivers/gpu/drm/sun4i/sun4i_tcon.c | 14 ++++++++++++-- drivers/gpu/drm/sun4i/sun4i_tcon.h | 4 ++++ 6 files changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index d660741ba475..95a77c6a9161 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -19,6 +19,7 @@ #include #include +#include #include #include "sun4i_backend.h" @@ -310,7 +311,6 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, if (!backend) return -ENOMEM; dev_set_drvdata(dev, backend); - drv->backend = backend; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); @@ -369,6 +369,8 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, } } + list_add_tail(&backend->list, &drv->backend_list); + /* Reset the registers */ for (i = 0x800; i < 0x1000; i += 4) regmap_write(backend->regs, i, 0); @@ -400,6 +402,8 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master, { struct sun4i_backend *backend = dev_get_drvdata(dev); + list_del(&backend->list); + if (of_device_is_compatible(dev->of_node, "allwinner,sun8i-a33-display-backend")) sun4i_backend_free_sat(dev); diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 83e63cc702b4..9c8287309c65 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -14,6 +14,7 @@ #define _SUN4I_BACKEND_H_ #include +#include #include #include @@ -149,6 +150,9 @@ struct sun4i_backend { struct clk *sat_clk; struct reset_control *sat_reset; + + /* Backend list management */ + struct list_head list; }; void sun4i_backend_apply_color_correction(struct sun4i_backend *backend); diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.c b/drivers/gpu/drm/sun4i/sun4i_drv.c index 8ddd72cd5873..c52f7a9eb045 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.c +++ b/drivers/gpu/drm/sun4i/sun4i_drv.c @@ -91,6 +91,8 @@ static int sun4i_drv_bind(struct device *dev) goto free_drm; } drm->dev_private = drv; + INIT_LIST_HEAD(&drv->backend_list); + INIT_LIST_HEAD(&drv->tcon_list); ret = of_reserved_mem_device_init(dev); if (ret && ret != -ENODEV) { diff --git a/drivers/gpu/drm/sun4i/sun4i_drv.h b/drivers/gpu/drm/sun4i/sun4i_drv.h index 5df50126ff52..250c29017ef5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_drv.h +++ b/drivers/gpu/drm/sun4i/sun4i_drv.h @@ -14,11 +14,12 @@ #define _SUN4I_DRV_H_ #include +#include #include struct sun4i_drv { - struct sun4i_backend *backend; - struct sun4i_tcon *tcon; + struct list_head backend_list; + struct list_head tcon_list; struct drm_fbdev_cma *fbdev; }; diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 9a83a85529ac..5adb643ed41d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -25,6 +25,7 @@ #include #include +#include "sun4i_backend.h" #include "sun4i_crtc.h" #include "sun4i_dotclock.h" #include "sun4i_drv.h" @@ -407,14 +408,18 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, { struct drm_device *drm = data; struct sun4i_drv *drv = drm->dev_private; + struct sun4i_backend *backend; struct sun4i_tcon *tcon; int ret; + /* Wait for a backend to be registered */ + if (list_empty(&drv->backend_list)) + return -EPROBE_DEFER; + tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL); if (!tcon) return -ENOMEM; dev_set_drvdata(dev, tcon); - drv->tcon = tcon; tcon->drm = drm; tcon->dev = dev; tcon->quirks = of_device_get_match_data(dev); @@ -459,7 +464,9 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, goto err_free_dotclock; } - tcon->crtc = sun4i_crtc_init(drm, drv->backend, tcon); + backend = list_first_entry(&drv->backend_list, + struct sun4i_backend, list); + tcon->crtc = sun4i_crtc_init(drm, backend, tcon); if (IS_ERR(tcon->crtc)) { dev_err(dev, "Couldn't create our CRTC\n"); ret = PTR_ERR(tcon->crtc); @@ -470,6 +477,8 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, if (ret < 0) goto err_free_clocks; + list_add_tail(&tcon->list, &drv->tcon_list); + return 0; err_free_dotclock: @@ -486,6 +495,7 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master, { struct sun4i_tcon *tcon = dev_get_drvdata(dev); + list_del(&tcon->list); sun4i_dclk_free(tcon); sun4i_tcon_free_clocks(tcon); } diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index f636343a935d..1bda4d183eec 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -17,6 +17,7 @@ #include #include +#include #include #define SUN4I_TCON_GCTL_REG 0x0 @@ -172,6 +173,9 @@ struct sun4i_tcon { /* Associated crtc */ struct sun4i_crtc *crtc; + + /* TCON list management */ + struct list_head list; }; struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node); -- cgit From fdde6e7bcd5e2de4da6da7b0aab9676c478f319e Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 21 Apr 2017 16:38:51 +0800 Subject: drm/sun4i: backend: Drop trailing 0 from backend in error message Now that we support multiple instances of backends, the trailing 0 implying only one backend no longer makes sense. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 95a77c6a9161..e17e20036aa3 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -320,7 +320,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, backend->regs = devm_regmap_init_mmio(dev, regs, &sun4i_backend_regmap_config); if (IS_ERR(backend->regs)) { - dev_err(dev, "Couldn't create the backend0 regmap\n"); + dev_err(dev, "Couldn't create the backend regmap\n"); return PTR_ERR(backend->regs); } -- cgit From da3a1c30dc10858b39a759432d8141f42b8529e8 Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 21 Apr 2017 16:38:52 +0800 Subject: drm/sun4i: backend: Fetch backend ID from device tree Some Allwinner SoCs have 2 display pipelines, as in 2 of each components, including the frontend, backend, TCON, and any other extras. As the backend and TCON are always paired together and form the CRTC, we need to know which backend or TCON we are currently probing, so we can pair them when initializing the CRTC. This patch figures out the backend's ID from the device tree and stores it in the backend's data structure. It does this by looking at the "reg" property of any remote endpoints connected to the backend's input port. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 44 +++++++++++++++++++++++++++++++++++ drivers/gpu/drm/sun4i/sun4i_backend.h | 2 ++ 2 files changed, 46 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index e17e20036aa3..0b4222312e49 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "sun4i_backend.h" @@ -289,6 +290,45 @@ static int sun4i_backend_free_sat(struct device *dev) { return 0; } +/* + * The display backend can take video output from the display frontend, or + * the display enhancement unit on the A80, as input for one it its layers. + * This relationship within the display pipeline is encoded in the device + * tree with of_graph, and we use it here to figure out which backend, if + * there are 2 or more, we are currently probing. The number would be in + * the "reg" property of the upstream output port endpoint. + */ +static int sun4i_backend_of_get_id(struct device_node *node) +{ + struct device_node *port, *ep; + int ret = -EINVAL; + + /* input is port 0 */ + port = of_graph_get_port_by_id(node, 0); + if (!port) + return -EINVAL; + + /* try finding an upstream endpoint */ + for_each_available_child_of_node(port, ep) { + struct device_node *remote; + u32 reg; + + remote = of_parse_phandle(ep, "remote-endpoint", 0); + if (!remote) + continue; + + ret = of_property_read_u32(remote, "reg", ®); + if (ret) + continue; + + ret = reg; + } + + of_node_put(port); + + return ret; +} + static struct regmap_config sun4i_backend_regmap_config = { .reg_bits = 32, .val_bits = 32, @@ -312,6 +352,10 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, return -ENOMEM; dev_set_drvdata(dev, backend); + backend->id = sun4i_backend_of_get_id(dev->of_node); + if (backend->id < 0) + return backend->id; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 9c8287309c65..45b7fc110590 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -151,6 +151,8 @@ struct sun4i_backend { struct clk *sat_clk; struct reset_control *sat_reset; + int id; + /* Backend list management */ struct list_head list; }; -- cgit From 2c03e2fb063f33694e35bbade6d9186274b9a02f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 21 Apr 2017 16:38:53 +0800 Subject: drm/sun4i: backend: Save pointer to device tree node Save a pointer to the backend's underlying device tree node in its data structure. This will be used later for downstream tcons to find and match their respective upstream backends. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 1 + drivers/gpu/drm/sun4i/sun4i_backend.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index 0b4222312e49..e9eca057ff35 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -352,6 +352,7 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, return -ENOMEM; dev_set_drvdata(dev, backend); + backend->node = dev->of_node; backend->id = sun4i_backend_of_get_id(dev->of_node); if (backend->id < 0) return backend->id; diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 45b7fc110590..6327a2985fe6 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -140,6 +141,7 @@ #define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p))) struct sun4i_backend { + struct device_node *node; struct regmap *regs; struct reset_control *reset; -- cgit From b317fa3ba11a10eee45c3e64d6396015ff87e8dc Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 21 Apr 2017 16:38:54 +0800 Subject: drm/sun4i: tcon: Find matching display backend by device node matching With Allwinner's Display Engine 1.0, each TCON's input is tied to a specific display backend, and the 2 comprise what is known as a crtc in DRM KMS land: The layer, framebuffer, and compositing functions are provided by the backend, while the TCON provides the display timing signals and vblank interrupts. This 1 to 1 relationship is represented in the device tree. On some systems there is an intermediate DRC component. Pointers to both matching components must be provided when initializing the crtc. As the backend is always registered before the associated tcon, we can recursively search upwards through the of_graph to find the matching backend. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 55 +++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 5adb643ed41d..b13a7c2029df 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -403,6 +403,53 @@ static int sun4i_tcon_init_regmap(struct device *dev, return 0; } +/* + * On SoCs with the old display pipeline design (Display Engine 1.0), + * the TCON is always tied to just one backend. Hence we can traverse + * the of_graph upwards to find the backend our tcon is connected to, + * and take its ID as our own. + * + * We can either identify backends from their compatible strings, which + * means maintaining a large list of them. Or, since the backend is + * registered and binded before the TCON, we can just go through the + * list of registered backends and compare the device node. + */ +static struct sun4i_backend *sun4i_tcon_find_backend(struct sun4i_drv *drv, + struct device_node *node) +{ + struct device_node *port, *ep, *remote; + struct sun4i_backend *backend; + + port = of_graph_get_port_by_id(node, 0); + if (!port) + return ERR_PTR(-EINVAL); + + for_each_available_child_of_node(port, ep) { + remote = of_graph_get_remote_port_parent(ep); + if (!remote) + continue; + + /* does this node match any registered backends? */ + list_for_each_entry(backend, &drv->backend_list, list) { + if (remote == backend->node) { + of_node_put(remote); + of_node_put(port); + return backend; + } + } + + /* keep looking through upstream ports */ + backend = sun4i_tcon_find_backend(drv, remote); + if (!IS_ERR(backend)) { + of_node_put(remote); + of_node_put(port); + return backend; + } + } + + return ERR_PTR(-EINVAL); +} + static int sun4i_tcon_bind(struct device *dev, struct device *master, void *data) { @@ -412,9 +459,11 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, struct sun4i_tcon *tcon; int ret; - /* Wait for a backend to be registered */ - if (list_empty(&drv->backend_list)) + backend = sun4i_tcon_find_backend(drv, dev->of_node); + if (IS_ERR(backend)) { + dev_err(dev, "Couldn't find matching backend\n"); return -EPROBE_DEFER; + } tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL); if (!tcon) @@ -464,8 +513,6 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, goto err_free_dotclock; } - backend = list_first_entry(&drv->backend_list, - struct sun4i_backend, list); tcon->crtc = sun4i_crtc_init(drm, backend, tcon); if (IS_ERR(tcon->crtc)) { dev_err(dev, "Couldn't create our CRTC\n"); -- cgit From d281c862de30381c144145a75ec1f0d5efc307ae Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 21 Apr 2017 16:38:55 +0800 Subject: drm/sun4i: tcon: Copy ID from associated backend The tcons and backends have a one-to-one relationship. Their IDs, or indexes in the documentation, are also the same. Copy the ID from the associated backend and save it in the tcon structure. This will later be used when we add support for the output data path muxes. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_tcon.c | 1 + drivers/gpu/drm/sun4i/sun4i_tcon.h | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index b13a7c2029df..5d7866fce78b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -471,6 +471,7 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, dev_set_drvdata(dev, tcon); tcon->drm = drm; tcon->dev = dev; + tcon->id = backend->id; tcon->quirks = of_device_get_match_data(dev); tcon->lcd_rst = devm_reset_control_get(dev, "lcd"); diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h index 1bda4d183eec..d37e1e2ed60e 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.h +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h @@ -174,6 +174,8 @@ struct sun4i_tcon { /* Associated crtc */ struct sun4i_crtc *crtc; + int id; + /* TCON list management */ struct list_head list; }; -- cgit From 86cf6788a661b8cb459f259e373c5daf09221abe Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 25 Apr 2017 23:25:04 +0800 Subject: drm/sun4i: Set TCON clock inside sun4i_tconX_mode_set Currently we are configuring the TCON's dot clock or special clock directly from the encoder mode_set functions. Since we already provide mode_set helper functions for the TCON's 2 channels, we can set the respective clock from those helpers, and reduce the exposure of the TCON's internals. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_rgb.c | 2 -- drivers/gpu/drm/sun4i/sun4i_tcon.c | 6 ++++++ drivers/gpu/drm/sun4i/sun4i_tv.c | 2 -- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c index 67f0b91a99de..c9bbb3b560a5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c @@ -176,8 +176,6 @@ static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder, sun4i_tcon0_mode_set(tcon, mode); - clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); - /* FIXME: This seems to be board specific */ clk_set_phase(tcon->dclk, 120); } diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 5d7866fce78b..8b6aaa60037d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -130,6 +130,9 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon, u8 clk_delay; u32 val = 0; + /* Configure the dot clock */ + clk_set_rate(tcon->dclk, mode->crtc_clock * 1000); + /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 0); regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG, @@ -205,6 +208,9 @@ void sun4i_tcon1_mode_set(struct sun4i_tcon *tcon, WARN_ON(!tcon->quirks->has_channel_1); + /* Configure the dot clock */ + clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000); + /* Adjust clock delay */ clk_delay = sun4i_tcon_get_clk_delay(mode, 1); regmap_update_bits(tcon->regs, SUN4I_TCON1_CTL_REG, diff --git a/drivers/gpu/drm/sun4i/sun4i_tv.c b/drivers/gpu/drm/sun4i/sun4i_tv.c index 49c49431a053..542da220818b 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tv.c +++ b/drivers/gpu/drm/sun4i/sun4i_tv.c @@ -486,8 +486,6 @@ static void sun4i_tv_mode_set(struct drm_encoder *encoder, SUN4I_TVE_RESYNC_FIELD : 0)); regmap_write(tv->regs, SUN4I_TVE_SLAVE_REG, 0); - - clk_set_rate(tcon->sclk1, mode->crtc_clock * 1000); } static struct drm_encoder_helper_funcs sun4i_tv_helper_funcs = { -- cgit From cf80aeef958f2e5b0041c72b567ae949f5b2738d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Tue, 25 Apr 2017 23:25:05 +0800 Subject: drm/sun4i: backend: Clarify sun4i_backend_layer_enable debug message sun4i_backend_layer_enable can be called to enable or disable a layer. However the debug message always says "Enable", which is confusing. This patch makes the debug message vary according to the enable state. Signed-off-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_backend.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index e9eca057ff35..e53107418add 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -73,7 +73,8 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend, { u32 val; - DRM_DEBUG_DRIVER("Enabling layer %d\n", layer); + DRM_DEBUG_DRIVER("%sabling layer %d\n", enable ? "En" : "Dis", + layer); if (enable) val = SUN4I_BACKEND_MODCTL_LAY_EN(layer); -- cgit From 7921e1477a5327ff22cc38a0ec74ace5d26dbba9 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Mon, 15 May 2017 00:30:36 +0800 Subject: drm/sun4i: return only planes for layers created As we are going to add support for the Allwinner DE2 Mixer in sun4i-drm driver, we will finally have two types of layers. Each layer is bound to a drm_plane that is CRTC-specific, so we create them when initializing CRTC (calling sun4i_layers_init, which will be generalized in next patch). The drm_plane's will be used when creating CRTC, but the CRTC initialization code do not care other properties of the layer, so we let the sun4i_layers_init function return drm_plane's only. As we have no need to trace the layers after the CRTC is properly created, we drop the layers pointer in sun4i_crtc struct. Doing this uncouples the CRTC code from the type of layer (the sun4i_layers_init function name is still hardcoded and will be changed in the next patch), so that we can finally gain support for the mixer in DE2, which has different layers. Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/sun4i_crtc.c | 23 ++++++++++++----------- drivers/gpu/drm/sun4i/sun4i_crtc.h | 1 - drivers/gpu/drm/sun4i/sun4i_layer.c | 18 ++++++++++-------- drivers/gpu/drm/sun4i/sun4i_layer.h | 4 ++-- 4 files changed, 24 insertions(+), 22 deletions(-) (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 3c876c3a356a..708b3543d4e9 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -139,6 +139,7 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, struct sun4i_tcon *tcon) { struct sun4i_crtc *scrtc; + struct drm_plane **planes; struct drm_plane *primary = NULL, *cursor = NULL; int ret, i; @@ -149,22 +150,22 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, scrtc->tcon = tcon; /* Create our layers */ - scrtc->layers = sun4i_layers_init(drm, scrtc->backend); - if (IS_ERR(scrtc->layers)) { + planes = sun4i_layers_init(drm, scrtc); + if (IS_ERR(planes)) { dev_err(drm->dev, "Couldn't create the planes\n"); return NULL; } /* find primary and cursor planes for drm_crtc_init_with_planes */ - for (i = 0; scrtc->layers[i]; i++) { - struct sun4i_layer *layer = scrtc->layers[i]; + for (i = 0; planes[i]; i++) { + struct drm_plane *plane = planes[i]; - switch (layer->plane.type) { + switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY: - primary = &layer->plane; + primary = plane; break; case DRM_PLANE_TYPE_CURSOR: - cursor = &layer->plane; + cursor = plane; break; default: break; @@ -188,12 +189,12 @@ struct sun4i_crtc *sun4i_crtc_init(struct drm_device *drm, 1); /* Set possible_crtcs to this crtc for overlay planes */ - for (i = 0; scrtc->layers[i]; i++) { + for (i = 0; planes[i]; i++) { uint32_t possible_crtcs = BIT(drm_crtc_index(&scrtc->crtc)); - struct sun4i_layer *layer = scrtc->layers[i]; + struct drm_plane *plane = planes[i]; - if (layer->plane.type == DRM_PLANE_TYPE_OVERLAY) - layer->plane.possible_crtcs = possible_crtcs; + if (plane->type == DRM_PLANE_TYPE_OVERLAY) + plane->possible_crtcs = possible_crtcs; } return scrtc; diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.h b/drivers/gpu/drm/sun4i/sun4i_crtc.h index 230cb8f0d601..4dae3508424a 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.h +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.h @@ -19,7 +19,6 @@ struct sun4i_crtc { struct sun4i_backend *backend; struct sun4i_tcon *tcon; - struct sun4i_layer **layers; }; static inline struct sun4i_crtc *drm_crtc_to_sun4i_crtc(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.c b/drivers/gpu/drm/sun4i/sun4i_layer.c index f26bde5b9117..e1f03e1cc0ac 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.c +++ b/drivers/gpu/drm/sun4i/sun4i_layer.c @@ -16,6 +16,7 @@ #include #include "sun4i_backend.h" +#include "sun4i_crtc.h" #include "sun4i_layer.h" struct sun4i_plane_desc { @@ -128,15 +129,16 @@ static struct sun4i_layer *sun4i_layer_init_one(struct drm_device *drm, return layer; } -struct sun4i_layer **sun4i_layers_init(struct drm_device *drm, - struct sun4i_backend *backend) +struct drm_plane **sun4i_layers_init(struct drm_device *drm, + struct sun4i_crtc *crtc) { - struct sun4i_layer **layers; + struct drm_plane **planes; + struct sun4i_backend *backend = crtc->backend; int i; - layers = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1, - sizeof(*layers), GFP_KERNEL); - if (!layers) + planes = devm_kcalloc(drm->dev, ARRAY_SIZE(sun4i_backend_planes) + 1, + sizeof(*planes), GFP_KERNEL); + if (!planes) return ERR_PTR(-ENOMEM); /* @@ -178,8 +180,8 @@ struct sun4i_layer **sun4i_layers_init(struct drm_device *drm, SUN4I_BACKEND_ATTCTL_REG0_LAY_PIPESEL(plane->pipe)); layer->id = i; - layers[i] = layer; + planes[i] = &layer->plane; }; - return layers; + return planes; } diff --git a/drivers/gpu/drm/sun4i/sun4i_layer.h b/drivers/gpu/drm/sun4i/sun4i_layer.h index 4be1f0919df2..5ea5c994d6ea 100644 --- a/drivers/gpu/drm/sun4i/sun4i_layer.h +++ b/drivers/gpu/drm/sun4i/sun4i_layer.h @@ -26,7 +26,7 @@ plane_to_sun4i_layer(struct drm_plane *plane) return container_of(plane, struct sun4i_layer, plane); } -struct sun4i_layer **sun4i_layers_init(struct drm_device *drm, - struct sun4i_backend *backend); +struct drm_plane **sun4i_layers_init(struct drm_device *drm, + struct sun4i_crtc *crtc); #endif /* _SUN4I_LAYER_H_ */ -- cgit From 87969338436710638076d8083dda8b0de703f4a5 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Wed, 17 May 2017 22:47:17 +0800 Subject: drm/sun4i: abstract a engine type As we are going to add support for the Allwinner DE2 engine in sun4i-drm driver, we will finally have two types of display engines -- the DE1 backend and the DE2 mixer. They both do some display blending and feed graphics data to TCON, and is part of the "Display Engine" called by Allwinner, so I choose to call them both "engine" here. Abstract the engine type to a new struct with an ops struct, which contains functions that should be called outside the engine-specified code (in TCON, CRTC or TV Encoder code). In order to preserve bisectability, we also switch the backend and layer code in its own module. Signed-off-by: Icenowy Zheng Reviewed-by: Chen-Yu Tsai Signed-off-by: Maxime Ripard --- drivers/gpu/drm/sun4i/Makefile | 5 +- drivers/gpu/drm/sun4i/sun4i_backend.c | 78 +++++++++++++++------------- drivers/gpu/drm/sun4i/sun4i_backend.h | 19 +++---- drivers/gpu/drm/sun4i/sun4i_crtc.c | 11 ++-- drivers/gpu/drm/sun4i/sun4i_crtc.h | 4 +- drivers/gpu/drm/sun4i/sun4i_drv.c | 2 +- drivers/gpu/drm/sun4i/sun4i_drv.h | 2 +- drivers/gpu/drm/sun4i/sun4i_layer.c | 9 ++-- drivers/gpu/drm/sun4i/sun4i_layer.h | 4 +- drivers/gpu/drm/sun4i/sun4i_tcon.c | 38 ++++++++------ drivers/gpu/drm/sun4i/sun4i_tv.c | 9 ++-- drivers/gpu/drm/sun4i/sunxi_engine.h | 98 +++++++++++++++++++++++++++++++++++ 12 files changed, 192 insertions(+), 87 deletions(-) create mode 100644 drivers/gpu/drm/sun4i/sunxi_engine.h (limited to 'drivers/gpu') diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile index 59b757350a1f..a251fb36c951 100644 --- a/drivers/gpu/drm/sun4i/Makefile +++ b/drivers/gpu/drm/sun4i/Makefile @@ -5,9 +5,10 @@ sun4i-tcon-y += sun4i_tcon.o sun4i-tcon-y += sun4i_rgb.o sun4i-tcon-y += sun4i_dotclock.o sun4i-tcon-y += sun4i_crtc.o -sun4i-tcon-y += sun4i_layer.o + +sun4i-backend-y += sun4i_backend.o sun4i_layer.o obj-$(CONFIG_DRM_SUN4I) += sun4i-drm.o sun4i-tcon.o -obj-$(CONFIG_DRM_SUN4I) += sun4i_backend.o +obj-$(CONFIG_DRM_SUN4I) += sun4i-backend.o obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o obj-$(CONFIG_DRM_SUN4I) += sun4i_tv.o diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.c b/drivers/gpu/drm/sun4i/sun4i_backend.c index e53107418add..cf480218daa5 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.c +++ b/drivers/gpu/drm/sun4i/sun4i_backend.c @@ -25,6 +25,8 @@ #include "sun4i_backend.h" #include "sun4i_drv.h" +#include "sun4i_layer.h" +#include "sunxi_engine.h" static const u32 sunxi_rgb2yuv_coef[12] = { 0x00000107, 0x00000204, 0x00000064, 0x00000108, @@ -32,41 +34,38 @@ static const u32 sunxi_rgb2yuv_coef[12] = { 0x000001c1, 0x00003e88, 0x00003fb8, 0x00000808 }; -void sun4i_backend_apply_color_correction(struct sun4i_backend *backend) +static void sun4i_backend_apply_color_correction(struct sunxi_engine *engine) { int i; DRM_DEBUG_DRIVER("Applying RGB to YUV color correction\n"); /* Set color correction */ - regmap_write(backend->regs, SUN4I_BACKEND_OCCTL_REG, + regmap_write(engine->regs, SUN4I_BACKEND_OCCTL_REG, SUN4I_BACKEND_OCCTL_ENABLE); for (i = 0; i < 12; i++) - regmap_write(backend->regs, SUN4I_BACKEND_OCRCOEF_REG(i), + regmap_write(engine->regs, SUN4I_BACKEND_OCRCOEF_REG(i), sunxi_rgb2yuv_coef[i]); } -EXPORT_SYMBOL(sun4i_backend_apply_color_correction); -void sun4i_backend_disable_color_correction(struct sun4i_backend *backend) +static void sun4i_backend_disable_color_correction(struct sunxi_engine *engine) { DRM_DEBUG_DRIVER("Disabling color correction\n"); /* Disable color correction */ - regmap_update_bits(backend->regs, SUN4I_BACKEND_OCCTL_REG, + regmap_update_bits(engine->regs, SUN4I_BACKEND_OCCTL_REG, SUN4I_BACKEND_OCCTL_ENABLE, 0); } -EXPORT_SYMBOL(sun4i_backend_disable_color_correction); -void sun4i_backend_commit(struct sun4i_backend *backend) +static void sun4i_backend_commit(struct sunxi_engine *engine) { DRM_DEBUG_DRIVER("Committing changes\n"); - regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG, + regmap_write(engine->regs, SUN4I_BACKEND_REGBUFFCTL_REG, SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS | SUN4I_BACKEND_REGBUFFCTL_LOADCTL); } -EXPORT_SYMBOL(sun4i_backend_commit); void sun4i_backend_layer_enable(struct sun4i_backend *backend, int layer, bool enable) @@ -81,10 +80,9 @@ void sun4i_backend_layer_enable(struct sun4i_backend *backend, else val = 0; - regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG, + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, SUN4I_BACKEND_MODCTL_LAY_EN(layer), val); } -EXPORT_SYMBOL(sun4i_backend_layer_enable); static int sun4i_backend_drm_format_to_layer(struct drm_plane *plane, u32 format, u32 *mode) @@ -144,33 +142,33 @@ int sun4i_backend_update_layer_coord(struct sun4i_backend *backend, if (plane->type == DRM_PLANE_TYPE_PRIMARY) { DRM_DEBUG_DRIVER("Primary layer, updating global size W: %u H: %u\n", state->crtc_w, state->crtc_h); - regmap_write(backend->regs, SUN4I_BACKEND_DISSIZE_REG, + regmap_write(backend->engine.regs, SUN4I_BACKEND_DISSIZE_REG, SUN4I_BACKEND_DISSIZE(state->crtc_w, state->crtc_h)); } /* Set the line width */ DRM_DEBUG_DRIVER("Layer line width: %d bits\n", fb->pitches[0] * 8); - regmap_write(backend->regs, SUN4I_BACKEND_LAYLINEWIDTH_REG(layer), + regmap_write(backend->engine.regs, + SUN4I_BACKEND_LAYLINEWIDTH_REG(layer), fb->pitches[0] * 8); /* Set height and width */ DRM_DEBUG_DRIVER("Layer size W: %u H: %u\n", state->crtc_w, state->crtc_h); - regmap_write(backend->regs, SUN4I_BACKEND_LAYSIZE_REG(layer), + regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYSIZE_REG(layer), SUN4I_BACKEND_LAYSIZE(state->crtc_w, state->crtc_h)); /* Set base coordinates */ DRM_DEBUG_DRIVER("Layer coordinates X: %d Y: %d\n", state->crtc_x, state->crtc_y); - regmap_write(backend->regs, SUN4I_BACKEND_LAYCOOR_REG(layer), + regmap_write(backend->engine.regs, SUN4I_BACKEND_LAYCOOR_REG(layer), SUN4I_BACKEND_LAYCOOR(state->crtc_x, state->crtc_y)); return 0; } -EXPORT_SYMBOL(sun4i_backend_update_layer_coord); int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, int layer, struct drm_plane *plane) @@ -185,7 +183,7 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, interlaced = plane->state->crtc->state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE; - regmap_update_bits(backend->regs, SUN4I_BACKEND_MODCTL_REG, + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, SUN4I_BACKEND_MODCTL_ITLMOD_EN, interlaced ? SUN4I_BACKEND_MODCTL_ITLMOD_EN : 0); @@ -199,12 +197,12 @@ int sun4i_backend_update_layer_formats(struct sun4i_backend *backend, return ret; } - regmap_update_bits(backend->regs, SUN4I_BACKEND_ATTCTL_REG1(layer), + regmap_update_bits(backend->engine.regs, + SUN4I_BACKEND_ATTCTL_REG1(layer), SUN4I_BACKEND_ATTCTL_REG1_LAY_FBFMT, val); return 0; } -EXPORT_SYMBOL(sun4i_backend_update_layer_formats); int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, int layer, struct drm_plane *plane) @@ -232,19 +230,19 @@ int sun4i_backend_update_layer_buffer(struct sun4i_backend *backend, /* Write the 32 lower bits of the address (in bits) */ lo_paddr = paddr << 3; DRM_DEBUG_DRIVER("Setting address lower bits to 0x%x\n", lo_paddr); - regmap_write(backend->regs, SUN4I_BACKEND_LAYFB_L32ADD_REG(layer), + regmap_write(backend->engine.regs, + SUN4I_BACKEND_LAYFB_L32ADD_REG(layer), lo_paddr); /* And the upper bits */ hi_paddr = paddr >> 29; DRM_DEBUG_DRIVER("Setting address high bits to 0x%x\n", hi_paddr); - regmap_update_bits(backend->regs, SUN4I_BACKEND_LAYFB_H4ADD_REG, + regmap_update_bits(backend->engine.regs, SUN4I_BACKEND_LAYFB_H4ADD_REG, SUN4I_BACKEND_LAYFB_H4ADD_MSK(layer), SUN4I_BACKEND_LAYFB_H4ADD(layer, hi_paddr)); return 0; } -EXPORT_SYMBOL(sun4i_backend_update_layer_buffer); static int sun4i_backend_init_sat(struct device *dev) { struct sun4i_backend *backend = dev_get_drvdata(dev); @@ -330,6 +328,13 @@ static int sun4i_backend_of_get_id(struct device_node *node) return ret; } +static const struct sunxi_engine_ops sun4i_backend_engine_ops = { + .commit = sun4i_backend_commit, + .layers_init = sun4i_layers_init, + .apply_color_correction = sun4i_backend_apply_color_correction, + .disable_color_correction = sun4i_backend_disable_color_correction, +}; + static struct regmap_config sun4i_backend_regmap_config = { .reg_bits = 32, .val_bits = 32, @@ -353,21 +358,22 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, return -ENOMEM; dev_set_drvdata(dev, backend); - backend->node = dev->of_node; - backend->id = sun4i_backend_of_get_id(dev->of_node); - if (backend->id < 0) - return backend->id; + backend->engine.node = dev->of_node; + backend->engine.ops = &sun4i_backend_engine_ops; + backend->engine.id = sun4i_backend_of_get_id(dev->of_node); + if (backend->engine.id < 0) + return backend->engine.id; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); if (IS_ERR(regs)) return PTR_ERR(regs); - backend->regs = devm_regmap_init_mmio(dev, regs, - &sun4i_backend_regmap_config); - if (IS_ERR(backend->regs)) { + backend->engine.regs = devm_regmap_init_mmio(dev, regs, + &sun4i_backend_regmap_config); + if (IS_ERR(backend->engine.regs)) { dev_err(dev, "Couldn't create the backend regmap\n"); - return PTR_ERR(backend->regs); + return PTR_ERR(backend->engine.regs); } backend->reset = devm_reset_control_get(dev, NULL); @@ -415,18 +421,18 @@ static int sun4i_backend_bind(struct device *dev, struct device *master, } } - list_add_tail(&backend->list, &drv->backend_list); + list_add_tail(&backend->engine.list, &drv->engine_list); /* Reset the registers */ for (i = 0x800; i < 0x1000; i += 4) - regmap_write(backend->regs, i, 0); + regmap_write(backend->engine.regs, i, 0); /* Disable registers autoloading */ - regmap_write(backend->regs, SUN4I_BACKEND_REGBUFFCTL_REG, + regmap_write(backend->engine.regs, SUN4I_BACKEND_REGBUFFCTL_REG, SUN4I_BACKEND_REGBUFFCTL_AUTOLOAD_DIS); /* Enable the backend */ - regmap_write(backend->regs, SUN4I_BACKEND_MODCTL_REG, + regmap_write(backend->engine.regs, SUN4I_BACKEND_MODCTL_REG, SUN4I_BACKEND_MODCTL_DEBE_EN | SUN4I_BACKEND_MODCTL_START_CTL); @@ -448,7 +454,7 @@ static void sun4i_backend_unbind(struct device *dev, struct device *master, { struct sun4i_backend *backend = dev_get_drvdata(dev); - list_del(&backend->list); + list_del(&backend->engine.list); if (of_device_is_compatible(dev->of_node, "allwinner,sun8i-a33-display-backend")) diff --git a/drivers/gpu/drm/sun4i/sun4i_backend.h b/drivers/gpu/drm/sun4i/sun4i_backend.h index 6327a2985fe6..21945af67a9d 100644 --- a/drivers/gpu/drm/sun4i/sun4i_backend.h +++ b/drivers/gpu/drm/sun4i/sun4i_backend.h @@ -19,6 +19,8 @@ #include #include +#include "sunxi_engine.h" + #define SUN4I_BACKEND_MODCTL_REG 0x800 #define SUN4I_BACKEND_MODCTL_LINE_SEL BIT(29) #define SUN4I_BACKEND_MODCTL_ITLMOD_EN BIT(28) @@ -141,8 +143,7 @@ #define SUN4I_BACKEND_PIPE_OFF(p) (0x5000 + (0x400 * (p))) struct sun4i_backend { - struct device_node *node; - struct regmap *regs; + struct sunxi_engine engine; struct reset_control *reset; @@ -152,17 +153,13 @@ struct sun4i_backend { struct clk *sat_clk; struct reset_control *sat_reset; - - int id; - - /* Backend list management */ - struct list_head list; }; -void sun4i_backend_apply_color_correction(struct sun4i_backend *backend); -void sun4i_backend_disable_color_correction(struct sun4i_backend *backend); - -void sun4i_backend_commit(struct sun4i_backend *backend); +static inline struct sun4i_backend * +engine_to_sun4i_backend(struct sunxi_engine *engine) +{ + return container_of(engine, struct sun4i_backend, engine); +} void sun4i_backend_layer_enable(struct sun4i_backend *backend, int layer, bool enable); diff --git a/drivers/gpu/drm/sun4i/sun4i_crtc.c b/drivers/gpu/drm/sun4i/sun4i_crtc.c index 708b3543d4e9..f8c70439d1e2 100644 --- a/drivers/gpu/drm/sun4i/sun4i_crtc.c +++ b/drivers/gpu/drm/sun4i/sun4i_crtc.c @@ -25,10 +25,9 @@ #include