Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.15.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2021 MediaTek Inc.
  4 */
  5
  6#include <linux/clk.h>
  7#include <linux/component.h>
  8#include <linux/module.h>
  9#include <linux/of.h>
 10#include <linux/platform_device.h>
 11#include <linux/soc/mediatek/mtk-cmdq.h>
 12
 13#include "mtk_crtc.h"
 14#include "mtk_ddp_comp.h"
 15#include "mtk_disp_drv.h"
 16#include "mtk_drm_drv.h"
 17
 18#define DISP_CCORR_EN				0x0000
 19#define CCORR_EN					BIT(0)
 20#define DISP_CCORR_CFG				0x0020
 21#define CCORR_RELAY_MODE				BIT(0)
 22#define CCORR_ENGINE_EN					BIT(1)
 23#define CCORR_GAMMA_OFF					BIT(2)
 24#define CCORR_WGAMUT_SRC_CLIP				BIT(3)
 25#define DISP_CCORR_SIZE				0x0030
 26#define DISP_CCORR_COEF_0			0x0080
 27#define DISP_CCORR_COEF_1			0x0084
 28#define DISP_CCORR_COEF_2			0x0088
 29#define DISP_CCORR_COEF_3			0x008C
 30#define DISP_CCORR_COEF_4			0x0090
 31
 32struct mtk_disp_ccorr_data {
 33	u32 matrix_bits;
 34};
 35
 36struct mtk_disp_ccorr {
 37	struct clk *clk;
 38	void __iomem *regs;
 39	struct cmdq_client_reg cmdq_reg;
 40	const struct mtk_disp_ccorr_data	*data;
 41};
 42
 43int mtk_ccorr_clk_enable(struct device *dev)
 44{
 45	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
 46
 47	return clk_prepare_enable(ccorr->clk);
 48}
 49
 50void mtk_ccorr_clk_disable(struct device *dev)
 51{
 52	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
 53
 54	clk_disable_unprepare(ccorr->clk);
 55}
 56
 57void mtk_ccorr_config(struct device *dev, unsigned int w,
 58			     unsigned int h, unsigned int vrefresh,
 59			     unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
 60{
 61	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
 62
 63	mtk_ddp_write(cmdq_pkt, w << 16 | h, &ccorr->cmdq_reg, ccorr->regs,
 64		      DISP_CCORR_SIZE);
 65	mtk_ddp_write(cmdq_pkt, CCORR_ENGINE_EN, &ccorr->cmdq_reg, ccorr->regs,
 66		      DISP_CCORR_CFG);
 67}
 68
 69void mtk_ccorr_start(struct device *dev)
 70{
 71	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
 72
 73	writel(CCORR_EN, ccorr->regs + DISP_CCORR_EN);
 74}
 75
 76void mtk_ccorr_stop(struct device *dev)
 77{
 78	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
 79
 80	writel_relaxed(0x0, ccorr->regs + DISP_CCORR_EN);
 81}
 82
 83/* Converts a DRM S31.32 value to the HW S1.n format. */
 84static u16 mtk_ctm_s31_32_to_s1_n(u64 in, u32 n)
 85{
 86	u16 r;
 87
 88	/* Sign bit. */
 89	r = in & BIT_ULL(63) ? BIT(n + 1) : 0;
 90
 91	if ((in & GENMASK_ULL(62, 33)) > 0) {
 92		/* identity value 0x100000000 -> 0x400(mt8183), */
 93		/* identity value 0x100000000 -> 0x800(mt8192), */
 94		/* if bigger this, set it to max 0x7ff. */
 95		r |= GENMASK(n, 0);
 96	} else {
 97		/* take the n+1 most important bits. */
 98		r |= (in >> (32 - n)) & GENMASK(n, 0);
 99	}
100
101	return r;
102}
103
104void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state)
105{
106	struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
107	struct drm_property_blob *blob = state->ctm;
108	struct drm_color_ctm *ctm;
109	const u64 *input;
110	uint16_t coeffs[9] = { 0 };
111	int i;
112	struct cmdq_pkt *cmdq_pkt = NULL;
113	u32 matrix_bits = ccorr->data->matrix_bits;
114
115	if (!blob)
116		return;
117
118	ctm = (struct drm_color_ctm *)blob->data;
119	input = ctm->matrix;
120
121	for (i = 0; i < ARRAY_SIZE(coeffs); i++)
122		coeffs[i] = mtk_ctm_s31_32_to_s1_n(input[i], matrix_bits);
123
124	mtk_ddp_write(cmdq_pkt, coeffs[0] << 16 | coeffs[1],
125		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_0);
126	mtk_ddp_write(cmdq_pkt, coeffs[2] << 16 | coeffs[3],
127		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_1);
128	mtk_ddp_write(cmdq_pkt, coeffs[4] << 16 | coeffs[5],
129		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_2);
130	mtk_ddp_write(cmdq_pkt, coeffs[6] << 16 | coeffs[7],
131		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_3);
132	mtk_ddp_write(cmdq_pkt, coeffs[8] << 16,
133		      &ccorr->cmdq_reg, ccorr->regs, DISP_CCORR_COEF_4);
134}
135
136static int mtk_disp_ccorr_bind(struct device *dev, struct device *master,
137			       void *data)
138{
139	return 0;
140}
141
142static void mtk_disp_ccorr_unbind(struct device *dev, struct device *master,
143				  void *data)
144{
145}
146
147static const struct component_ops mtk_disp_ccorr_component_ops = {
148	.bind	= mtk_disp_ccorr_bind,
149	.unbind	= mtk_disp_ccorr_unbind,
150};
151
152static int mtk_disp_ccorr_probe(struct platform_device *pdev)
153{
154	struct device *dev = &pdev->dev;
155	struct mtk_disp_ccorr *priv;
156	int ret;
157
158	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
159	if (!priv)
160		return -ENOMEM;
161
162	priv->clk = devm_clk_get(dev, NULL);
163	if (IS_ERR(priv->clk))
164		return dev_err_probe(dev, PTR_ERR(priv->clk),
165				     "failed to get ccorr clk\n");
166
167	priv->regs = devm_platform_ioremap_resource(pdev, 0);
168	if (IS_ERR(priv->regs))
169		return dev_err_probe(dev, PTR_ERR(priv->regs),
170				     "failed to ioremap ccorr\n");
171
172#if IS_REACHABLE(CONFIG_MTK_CMDQ)
173	ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
174	if (ret)
175		dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
176#endif
177
178	priv->data = of_device_get_match_data(dev);
179	platform_set_drvdata(pdev, priv);
180
181	ret = component_add(dev, &mtk_disp_ccorr_component_ops);
182	if (ret)
183		return dev_err_probe(dev, ret, "Failed to add component\n");
184
185	return 0;
186}
187
188static void mtk_disp_ccorr_remove(struct platform_device *pdev)
189{
190	component_del(&pdev->dev, &mtk_disp_ccorr_component_ops);
191}
192
193static const struct mtk_disp_ccorr_data mt8183_ccorr_driver_data = {
194	.matrix_bits = 10,
195};
196
197static const struct mtk_disp_ccorr_data mt8192_ccorr_driver_data = {
198	.matrix_bits = 11,
199};
200
201static const struct of_device_id mtk_disp_ccorr_driver_dt_match[] = {
202	{ .compatible = "mediatek,mt8183-disp-ccorr",
203	  .data = &mt8183_ccorr_driver_data},
204	{ .compatible = "mediatek,mt8192-disp-ccorr",
205	  .data = &mt8192_ccorr_driver_data},
206	{},
207};
208MODULE_DEVICE_TABLE(of, mtk_disp_ccorr_driver_dt_match);
209
210struct platform_driver mtk_disp_ccorr_driver = {
211	.probe		= mtk_disp_ccorr_probe,
212	.remove		= mtk_disp_ccorr_remove,
213	.driver		= {
214		.name	= "mediatek-disp-ccorr",
215		.of_match_table = mtk_disp_ccorr_driver_dt_match,
216	},
217};