File Index
Files and directories
Sign in
FILE

dc-tc.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/imx/dc/dc-tc.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright 2024 NXP
  4 */
  5
  6#include <linux/component.h>
  7#include <linux/mod_devicetable.h>
  8#include <linux/module.h>
  9#include <linux/platform_device.h>
 10#include <linux/regmap.h>
 11
 12#include "dc-drv.h"
 13#include "dc-de.h"
 14
 15#define TCON_CTRL	0x410
 16#define  CTRL_RST_VAL	0x01401408
 17
 18/* red: MAPBIT 29-20, green: MAPBIT 19-10, blue: MAPBIT 9-0 */
 19#define MAPBIT3_0	0x418
 20#define MAPBIT7_4	0x41c
 21#define MAPBIT11_8	0x420
 22#define MAPBIT15_12	0x424
 23#define MAPBIT19_16	0x428
 24#define MAPBIT23_20	0x42c
 25#define MAPBIT27_24	0x430
 26#define MAPBIT31_28	0x434
 27
 28static const struct dc_subdev_info dc_tc_info[] = {
 29	{ .reg_start = 0x5618c800, .id = 0, },
 30	{ .reg_start = 0x5618e400, .id = 1, },
 31};
 32
 33static const struct regmap_range dc_tc_regmap_ranges[] = {
 34	regmap_reg_range(TCON_CTRL, TCON_CTRL),
 35	regmap_reg_range(MAPBIT3_0, MAPBIT31_28),
 36};
 37
 38static const struct regmap_access_table dc_tc_regmap_access_table = {
 39	.yes_ranges = dc_tc_regmap_ranges,
 40	.n_yes_ranges = ARRAY_SIZE(dc_tc_regmap_ranges),
 41};
 42
 43static const struct regmap_config dc_tc_regmap_config = {
 44	.reg_bits = 32,
 45	.reg_stride = 4,
 46	.val_bits = 32,
 47	.fast_io = true,
 48	.wr_table = &dc_tc_regmap_access_table,
 49	.rd_table = &dc_tc_regmap_access_table,
 50	.max_register = MAPBIT31_28,
 51};
 52
 53/*
 54 * The pixels reach TCON are always in 30-bit BGR format.
 55 * The first bridge always receives pixels in 30-bit RGB format.
 56 * So, map the format to MEDIA_BUS_FMT_RGB101010_1X30.
 57 */
 58static const u32 dc_tc_mapbit[] = {
 59	0x17161514, 0x1b1a1918, 0x0b0a1d1c, 0x0f0e0d0c,
 60	0x13121110, 0x03020100, 0x07060504, 0x00000908,
 61};
 62
 63void dc_tc_init(struct dc_tc *tc)
 64{
 65	/* reset TCON_CTRL to POR default so that TCON works in bypass mode */
 66	regmap_write(tc->reg, TCON_CTRL, CTRL_RST_VAL);
 67
 68	/* set format */
 69	regmap_bulk_write(tc->reg, MAPBIT3_0, dc_tc_mapbit,
 70			  ARRAY_SIZE(dc_tc_mapbit));
 71}
 72
 73static int dc_tc_bind(struct device *dev, struct device *master, void *data)
 74{
 75	struct platform_device *pdev = to_platform_device(dev);
 76	struct dc_drm_device *dc_drm = data;
 77	struct resource *res;
 78	void __iomem *base;
 79	struct dc_tc *tc;
 80	int id;
 81
 82	tc = devm_kzalloc(dev, sizeof(*tc), GFP_KERNEL);
 83	if (!tc)
 84		return -ENOMEM;
 85
 86	base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
 87	if (IS_ERR(base))
 88		return PTR_ERR(base);
 89
 90	tc->reg = devm_regmap_init_mmio(dev, base, &dc_tc_regmap_config);
 91	if (IS_ERR(tc->reg))
 92		return PTR_ERR(tc->reg);
 93
 94	id = dc_subdev_get_id(dc_tc_info, ARRAY_SIZE(dc_tc_info), res);
 95	if (id < 0) {
 96		dev_err(dev, "failed to get instance number: %d\n", id);
 97		return id;
 98	}
 99
100	tc->dev = dev;
101	dc_drm->tc[id] = tc;
102
103	return 0;
104}
105
106static const struct component_ops dc_tc_ops = {
107	.bind = dc_tc_bind,
108};
109
110static int dc_tc_probe(struct platform_device *pdev)
111{
112	int ret;
113
114	ret = component_add(&pdev->dev, &dc_tc_ops);
115	if (ret)
116		return dev_err_probe(&pdev->dev, ret,
117				     "failed to add component\n");
118
119	return 0;
120}
121
122static void dc_tc_remove(struct platform_device *pdev)
123{
124	component_del(&pdev->dev, &dc_tc_ops);
125}
126
127static const struct of_device_id dc_tc_dt_ids[] = {
128	{ .compatible = "fsl,imx8qxp-dc-tcon" },
129	{ /* sentinel */ }
130};
131MODULE_DEVICE_TABLE(of, dc_tc_dt_ids);
132
133struct platform_driver dc_tc_driver = {
134	.probe = dc_tc_probe,
135	.remove = dc_tc_remove,
136	.driver = {
137		.name = "imx8-dc-tcon",
138		.suppress_bind_attrs = true,
139		.of_match_table = dc_tc_dt_ids,
140	},
141};
~/ Read-only file preview.