]> Git Repo - linux.git/blob - drivers/gpu/drm/mediatek/mtk_disp_aal.c
Merge patch series "riscv: Extension parsing fixes"
[linux.git] / drivers / gpu / drm / mediatek / mtk_disp_aal.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2021 MediaTek Inc.
4  */
5
6 #include <linux/bitfield.h>
7 #include <linux/clk.h>
8 #include <linux/component.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/platform_device.h>
12 #include <linux/soc/mediatek/mtk-cmdq.h>
13
14 #include "mtk_crtc.h"
15 #include "mtk_ddp_comp.h"
16 #include "mtk_disp_drv.h"
17 #include "mtk_drm_drv.h"
18
19 #define DISP_AAL_EN                             0x0000
20 #define AAL_EN                                          BIT(0)
21 #define DISP_AAL_CFG                            0x0020
22 #define AAL_RELAY_MODE                                  BIT(0)
23 #define AAL_GAMMA_LUT_EN                                BIT(1)
24 #define DISP_AAL_SIZE                           0x0030
25 #define DISP_AAL_SIZE_HSIZE                             GENMASK(28, 16)
26 #define DISP_AAL_SIZE_VSIZE                             GENMASK(12, 0)
27 #define DISP_AAL_OUTPUT_SIZE                    0x04d8
28 #define DISP_AAL_GAMMA_LUT                      0x0700
29 #define DISP_AAL_GAMMA_LUT_R                            GENMASK(29, 20)
30 #define DISP_AAL_GAMMA_LUT_G                            GENMASK(19, 10)
31 #define DISP_AAL_GAMMA_LUT_B                            GENMASK(9, 0)
32 #define DISP_AAL_LUT_BITS                       10
33 #define DISP_AAL_LUT_SIZE                       512
34
35 struct mtk_disp_aal_data {
36         bool has_gamma;
37 };
38
39  /**
40   * struct mtk_disp_aal - Display Adaptive Ambient Light driver structure
41   * @clk:      clock for DISP_AAL controller
42   * @regs:     MMIO registers base
43   * @cmdq_reg: CMDQ Client register
44   * @data:     platform specific data for DISP_AAL
45   */
46 struct mtk_disp_aal {
47         struct clk *clk;
48         void __iomem *regs;
49         struct cmdq_client_reg cmdq_reg;
50         const struct mtk_disp_aal_data *data;
51 };
52
53 int mtk_aal_clk_enable(struct device *dev)
54 {
55         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
56
57         return clk_prepare_enable(aal->clk);
58 }
59
60 void mtk_aal_clk_disable(struct device *dev)
61 {
62         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
63
64         clk_disable_unprepare(aal->clk);
65 }
66
67 void mtk_aal_config(struct device *dev, unsigned int w,
68                            unsigned int h, unsigned int vrefresh,
69                            unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
70 {
71         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
72         u32 sz;
73
74         sz = FIELD_PREP(DISP_AAL_SIZE_HSIZE, w);
75         sz |= FIELD_PREP(DISP_AAL_SIZE_VSIZE, h);
76
77         mtk_ddp_write(cmdq_pkt, sz, &aal->cmdq_reg, aal->regs, DISP_AAL_SIZE);
78         mtk_ddp_write(cmdq_pkt, sz, &aal->cmdq_reg, aal->regs, DISP_AAL_OUTPUT_SIZE);
79 }
80
81 /**
82  * mtk_aal_gamma_get_lut_size() - Get gamma LUT size for AAL
83  * @dev: Pointer to struct device
84  *
85  * Return: 0 if gamma control not supported in AAL or gamma LUT size
86  */
87 unsigned int mtk_aal_gamma_get_lut_size(struct device *dev)
88 {
89         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
90
91         if (aal->data && aal->data->has_gamma)
92                 return DISP_AAL_LUT_SIZE;
93         return 0;
94 }
95
96 void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state)
97 {
98         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
99         struct drm_color_lut *lut;
100         unsigned int i;
101         u32 cfg_val;
102
103         /* If gamma is not supported in AAL, go out immediately */
104         if (!(aal->data && aal->data->has_gamma))
105                 return;
106
107         /* Also, if there's no gamma lut there's nothing to do here. */
108         if (!state->gamma_lut)
109                 return;
110
111         lut = (struct drm_color_lut *)state->gamma_lut->data;
112         for (i = 0; i < DISP_AAL_LUT_SIZE; i++) {
113                 struct drm_color_lut hwlut = {
114                         .red = drm_color_lut_extract(lut[i].red, DISP_AAL_LUT_BITS),
115                         .green = drm_color_lut_extract(lut[i].green, DISP_AAL_LUT_BITS),
116                         .blue = drm_color_lut_extract(lut[i].blue, DISP_AAL_LUT_BITS)
117                 };
118                 u32 word;
119
120                 word = FIELD_PREP(DISP_AAL_GAMMA_LUT_R, hwlut.red);
121                 word |= FIELD_PREP(DISP_AAL_GAMMA_LUT_G, hwlut.green);
122                 word |= FIELD_PREP(DISP_AAL_GAMMA_LUT_B, hwlut.blue);
123                 writel(word, aal->regs + DISP_AAL_GAMMA_LUT + i * 4);
124         }
125
126         cfg_val = readl(aal->regs + DISP_AAL_CFG);
127
128         /* Enable the gamma table */
129         cfg_val |= FIELD_PREP(AAL_GAMMA_LUT_EN, 1);
130
131         /* Disable RELAY mode to pass the processed image */
132         cfg_val &= ~AAL_RELAY_MODE;
133
134         writel(cfg_val, aal->regs + DISP_AAL_CFG);
135 }
136
137 void mtk_aal_start(struct device *dev)
138 {
139         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
140
141         writel(AAL_EN, aal->regs + DISP_AAL_EN);
142 }
143
144 void mtk_aal_stop(struct device *dev)
145 {
146         struct mtk_disp_aal *aal = dev_get_drvdata(dev);
147
148         writel_relaxed(0x0, aal->regs + DISP_AAL_EN);
149 }
150
151 static int mtk_disp_aal_bind(struct device *dev, struct device *master,
152                                void *data)
153 {
154         return 0;
155 }
156
157 static void mtk_disp_aal_unbind(struct device *dev, struct device *master,
158                                   void *data)
159 {
160 }
161
162 static const struct component_ops mtk_disp_aal_component_ops = {
163         .bind   = mtk_disp_aal_bind,
164         .unbind = mtk_disp_aal_unbind,
165 };
166
167 static int mtk_disp_aal_probe(struct platform_device *pdev)
168 {
169         struct device *dev = &pdev->dev;
170         struct mtk_disp_aal *priv;
171         int ret;
172
173         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
174         if (!priv)
175                 return -ENOMEM;
176
177         priv->clk = devm_clk_get(dev, NULL);
178         if (IS_ERR(priv->clk)) {
179                 dev_err(dev, "failed to get aal clk\n");
180                 return PTR_ERR(priv->clk);
181         }
182
183         priv->regs = devm_platform_ioremap_resource(pdev, 0);
184         if (IS_ERR(priv->regs)) {
185                 dev_err(dev, "failed to ioremap aal\n");
186                 return PTR_ERR(priv->regs);
187         }
188
189 #if IS_REACHABLE(CONFIG_MTK_CMDQ)
190         ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
191         if (ret)
192                 dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
193 #endif
194
195         priv->data = of_device_get_match_data(dev);
196         platform_set_drvdata(pdev, priv);
197
198         ret = component_add(dev, &mtk_disp_aal_component_ops);
199         if (ret)
200                 dev_err(dev, "Failed to add component: %d\n", ret);
201
202         return ret;
203 }
204
205 static void mtk_disp_aal_remove(struct platform_device *pdev)
206 {
207         component_del(&pdev->dev, &mtk_disp_aal_component_ops);
208 }
209
210 static const struct mtk_disp_aal_data mt8173_aal_driver_data = {
211         .has_gamma = true,
212 };
213
214 static const struct of_device_id mtk_disp_aal_driver_dt_match[] = {
215         { .compatible = "mediatek,mt8173-disp-aal", .data = &mt8173_aal_driver_data },
216         { .compatible = "mediatek,mt8183-disp-aal" },
217         { /* sentinel */ }
218 };
219 MODULE_DEVICE_TABLE(of, mtk_disp_aal_driver_dt_match);
220
221 struct platform_driver mtk_disp_aal_driver = {
222         .probe          = mtk_disp_aal_probe,
223         .remove_new     = mtk_disp_aal_remove,
224         .driver         = {
225                 .name   = "mediatek-disp-aal",
226                 .of_match_table = mtk_disp_aal_driver_dt_match,
227         },
228 };
This page took 0.045563 seconds and 4 git commands to generate.