2 * Copyright (c) 2015 MediaTek Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <linux/clk.h>
16 #include <linux/component.h>
17 #include <linux/of_device.h>
18 #include <linux/of_irq.h>
19 #include <linux/platform_device.h>
21 #include "mtk_drm_crtc.h"
22 #include "mtk_drm_ddp_comp.h"
24 #define DISP_REG_RDMA_INT_ENABLE 0x0000
25 #define DISP_REG_RDMA_INT_STATUS 0x0004
26 #define RDMA_TARGET_LINE_INT BIT(5)
27 #define RDMA_FIFO_UNDERFLOW_INT BIT(4)
28 #define RDMA_EOF_ABNORMAL_INT BIT(3)
29 #define RDMA_FRAME_END_INT BIT(2)
30 #define RDMA_FRAME_START_INT BIT(1)
31 #define RDMA_REG_UPDATE_INT BIT(0)
32 #define DISP_REG_RDMA_GLOBAL_CON 0x0010
33 #define RDMA_ENGINE_EN BIT(0)
34 #define DISP_REG_RDMA_SIZE_CON_0 0x0014
35 #define DISP_REG_RDMA_SIZE_CON_1 0x0018
36 #define DISP_REG_RDMA_TARGET_LINE 0x001c
37 #define DISP_REG_RDMA_FIFO_CON 0x0040
38 #define RDMA_FIFO_UNDERFLOW_EN BIT(31)
39 #define RDMA_FIFO_PSEUDO_SIZE(bytes) (((bytes) / 16) << 16)
40 #define RDMA_OUTPUT_VALID_FIFO_THRESHOLD(bytes) ((bytes) / 16)
43 * struct mtk_disp_rdma - DISP_RDMA driver structure
44 * @ddp_comp - structure containing type enum and hardware resources
45 * @crtc - associated crtc to report irq events to
47 struct mtk_disp_rdma
{
48 struct mtk_ddp_comp ddp_comp
;
49 struct drm_crtc
*crtc
;
52 static irqreturn_t
mtk_disp_rdma_irq_handler(int irq
, void *dev_id
)
54 struct mtk_disp_rdma
*priv
= dev_id
;
55 struct mtk_ddp_comp
*rdma
= &priv
->ddp_comp
;
57 /* Clear frame completion interrupt */
58 writel(0x0, rdma
->regs
+ DISP_REG_RDMA_INT_STATUS
);
63 mtk_crtc_ddp_irq(priv
->crtc
, rdma
);
68 static void rdma_update_bits(struct mtk_ddp_comp
*comp
, unsigned int reg
,
69 unsigned int mask
, unsigned int val
)
71 unsigned int tmp
= readl(comp
->regs
+ reg
);
73 tmp
= (tmp
& ~mask
) | (val
& mask
);
74 writel(tmp
, comp
->regs
+ reg
);
77 static void mtk_rdma_enable_vblank(struct mtk_ddp_comp
*comp
,
78 struct drm_crtc
*crtc
)
80 struct mtk_disp_rdma
*priv
= container_of(comp
, struct mtk_disp_rdma
,
84 rdma_update_bits(comp
, DISP_REG_RDMA_INT_ENABLE
, RDMA_FRAME_END_INT
,
88 static void mtk_rdma_disable_vblank(struct mtk_ddp_comp
*comp
)
90 struct mtk_disp_rdma
*priv
= container_of(comp
, struct mtk_disp_rdma
,
94 rdma_update_bits(comp
, DISP_REG_RDMA_INT_ENABLE
, RDMA_FRAME_END_INT
, 0);
97 static void mtk_rdma_start(struct mtk_ddp_comp
*comp
)
99 rdma_update_bits(comp
, DISP_REG_RDMA_GLOBAL_CON
, RDMA_ENGINE_EN
,
103 static void mtk_rdma_stop(struct mtk_ddp_comp
*comp
)
105 rdma_update_bits(comp
, DISP_REG_RDMA_GLOBAL_CON
, RDMA_ENGINE_EN
, 0);
108 static void mtk_rdma_config(struct mtk_ddp_comp
*comp
, unsigned int width
,
109 unsigned int height
, unsigned int vrefresh
)
111 unsigned int threshold
;
114 rdma_update_bits(comp
, DISP_REG_RDMA_SIZE_CON_0
, 0xfff, width
);
115 rdma_update_bits(comp
, DISP_REG_RDMA_SIZE_CON_1
, 0xfffff, height
);
118 * Enable FIFO underflow since DSI and DPI can't be blocked.
119 * Keep the FIFO pseudo size reset default of 8 KiB. Set the
120 * output threshold to 6 microseconds with 7/6 overhead to
121 * account for blanking, and with a pixel depth of 4 bytes:
123 threshold
= width
* height
* vrefresh
* 4 * 7 / 1000000;
124 reg
= RDMA_FIFO_UNDERFLOW_EN
|
125 RDMA_FIFO_PSEUDO_SIZE(SZ_8K
) |
126 RDMA_OUTPUT_VALID_FIFO_THRESHOLD(threshold
);
127 writel(reg
, comp
->regs
+ DISP_REG_RDMA_FIFO_CON
);
130 static const struct mtk_ddp_comp_funcs mtk_disp_rdma_funcs
= {
131 .config
= mtk_rdma_config
,
132 .start
= mtk_rdma_start
,
133 .stop
= mtk_rdma_stop
,
134 .enable_vblank
= mtk_rdma_enable_vblank
,
135 .disable_vblank
= mtk_rdma_disable_vblank
,
138 static int mtk_disp_rdma_bind(struct device
*dev
, struct device
*master
,
141 struct mtk_disp_rdma
*priv
= dev_get_drvdata(dev
);
142 struct drm_device
*drm_dev
= data
;
145 ret
= mtk_ddp_comp_register(drm_dev
, &priv
->ddp_comp
);
147 dev_err(dev
, "Failed to register component %s: %d\n",
148 dev
->of_node
->full_name
, ret
);
156 static void mtk_disp_rdma_unbind(struct device
*dev
, struct device
*master
,
159 struct mtk_disp_rdma
*priv
= dev_get_drvdata(dev
);
160 struct drm_device
*drm_dev
= data
;
162 mtk_ddp_comp_unregister(drm_dev
, &priv
->ddp_comp
);
165 static const struct component_ops mtk_disp_rdma_component_ops
= {
166 .bind
= mtk_disp_rdma_bind
,
167 .unbind
= mtk_disp_rdma_unbind
,
170 static int mtk_disp_rdma_probe(struct platform_device
*pdev
)
172 struct device
*dev
= &pdev
->dev
;
173 struct mtk_disp_rdma
*priv
;
178 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
182 irq
= platform_get_irq(pdev
, 0);
186 comp_id
= mtk_ddp_comp_get_id(dev
->of_node
, MTK_DISP_RDMA
);
188 dev_err(dev
, "Failed to identify by alias: %d\n", comp_id
);
192 ret
= mtk_ddp_comp_init(dev
, dev
->of_node
, &priv
->ddp_comp
, comp_id
,
193 &mtk_disp_rdma_funcs
);
195 dev_err(dev
, "Failed to initialize component: %d\n", ret
);
199 /* Disable and clear pending interrupts */
200 writel(0x0, priv
->ddp_comp
.regs
+ DISP_REG_RDMA_INT_ENABLE
);
201 writel(0x0, priv
->ddp_comp
.regs
+ DISP_REG_RDMA_INT_STATUS
);
203 ret
= devm_request_irq(dev
, irq
, mtk_disp_rdma_irq_handler
,
204 IRQF_TRIGGER_NONE
, dev_name(dev
), priv
);
206 dev_err(dev
, "Failed to request irq %d: %d\n", irq
, ret
);
210 platform_set_drvdata(pdev
, priv
);
212 ret
= component_add(dev
, &mtk_disp_rdma_component_ops
);
214 dev_err(dev
, "Failed to add component: %d\n", ret
);
219 static int mtk_disp_rdma_remove(struct platform_device
*pdev
)
221 component_del(&pdev
->dev
, &mtk_disp_rdma_component_ops
);
226 static const struct of_device_id mtk_disp_rdma_driver_dt_match
[] = {
227 { .compatible
= "mediatek,mt8173-disp-rdma", },
230 MODULE_DEVICE_TABLE(of
, mtk_disp_rdma_driver_dt_match
);
232 struct platform_driver mtk_disp_rdma_driver
= {
233 .probe
= mtk_disp_rdma_probe
,
234 .remove
= mtk_disp_rdma_remove
,
236 .name
= "mediatek-disp-rdma",
237 .owner
= THIS_MODULE
,
238 .of_match_table
= mtk_disp_rdma_driver_dt_match
,