Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * (C) COPYRIGHT 2018 ARM Limited. All rights reserved.
  4 * Author: James.Qian.Wang <james.qian.wang@arm.com>
  5 *
  6 */
  7#include <linux/io.h>
  8#include <linux/iommu.h>
  9#include <linux/of_device.h>
 10#include <linux/of_graph.h>
 11#include <linux/of_reserved_mem.h>
 12#include <linux/platform_device.h>
 13#include <linux/pm_runtime.h>
 14#include <linux/dma-mapping.h>
 15#ifdef CONFIG_DEBUG_FS
 16#include <linux/debugfs.h>
 17#include <linux/seq_file.h>
 18#endif
 19
 20#include <drm/drm_print.h>
 21
 22#include "komeda_dev.h"
 23
 24static int komeda_register_show(struct seq_file *sf, void *x)
 25{
 26	struct komeda_dev *mdev = sf->private;
 27	int i;
 28
 29	seq_puts(sf, "\n====== Komeda register dump =========\n");
 30
 31	pm_runtime_get_sync(mdev->dev);
 32
 33	if (mdev->funcs->dump_register)
 34		mdev->funcs->dump_register(mdev, sf);
 35
 36	for (i = 0; i < mdev->n_pipelines; i++)
 37		komeda_pipeline_dump_register(mdev->pipelines[i], sf);
 38
 39	pm_runtime_put(mdev->dev);
 40
 41	return 0;
 42}
 43
 44static int komeda_register_open(struct inode *inode, struct file *filp)
 45{
 46	return single_open(filp, komeda_register_show, inode->i_private);
 47}
 48
 49static const struct file_operations komeda_register_fops = {
 50	.owner		= THIS_MODULE,
 51	.open		= komeda_register_open,
 52	.read		= seq_read,
 53	.llseek		= seq_lseek,
 54	.release	= single_release,
 55};
 56
 57#ifdef CONFIG_DEBUG_FS
 58static void komeda_debugfs_init(struct komeda_dev *mdev)
 59{
 60	if (!debugfs_initialized())
 61		return;
 62
 63	mdev->debugfs_root = debugfs_create_dir("komeda", NULL);
 64	debugfs_create_file("register", 0444, mdev->debugfs_root,
 65			    mdev, &komeda_register_fops);
 66	debugfs_create_x16("err_verbosity", 0664, mdev->debugfs_root,
 67			   &mdev->err_verbosity);
 68}
 69#endif
 70
 71static ssize_t
 72core_id_show(struct device *dev, struct device_attribute *attr, char *buf)
 73{
 74	struct komeda_dev *mdev = dev_to_mdev(dev);
 75
 76	return snprintf(buf, PAGE_SIZE, "0x%08x\n", mdev->chip.core_id);
 77}
 78static DEVICE_ATTR_RO(core_id);
 79
 80static ssize_t
 81config_id_show(struct device *dev, struct device_attribute *attr, char *buf)
 82{
 83	struct komeda_dev *mdev = dev_to_mdev(dev);
 84	struct komeda_pipeline *pipe = mdev->pipelines[0];
 85	union komeda_config_id config_id;
 86	int i;
 87
 88	memset(&config_id, 0, sizeof(config_id));
 89
 90	config_id.max_line_sz = pipe->layers[0]->hsize_in.end;
 91	config_id.n_pipelines = mdev->n_pipelines;
 92	config_id.n_scalers = pipe->n_scalers;
 93	config_id.n_layers = pipe->n_layers;
 94	config_id.n_richs = 0;
 95	for (i = 0; i < pipe->n_layers; i++) {
 96		if (pipe->layers[i]->layer_type == KOMEDA_FMT_RICH_LAYER)
 97			config_id.n_richs++;
 98	}
 99	return snprintf(buf, PAGE_SIZE, "0x%08x\n", config_id.value);
100}
101static DEVICE_ATTR_RO(config_id);
102
103static ssize_t
104aclk_hz_show(struct device *dev, struct device_attribute *attr, char *buf)
105{
106	struct komeda_dev *mdev = dev_to_mdev(dev);
107
108	return snprintf(buf, PAGE_SIZE, "%lu\n", clk_get_rate(mdev->aclk));
109}
110static DEVICE_ATTR_RO(aclk_hz);
111
112static struct attribute *komeda_sysfs_entries[] = {
113	&dev_attr_core_id.attr,
114	&dev_attr_config_id.attr,
115	&dev_attr_aclk_hz.attr,
116	NULL,
117};
118
119static struct attribute_group komeda_sysfs_attr_group = {
120	.attrs = komeda_sysfs_entries,
121};
122
123static int komeda_parse_pipe_dt(struct komeda_pipeline *pipe)
124{
125	struct device_node *np = pipe->of_node;
126	struct clk *clk;
127
128	clk = of_clk_get_by_name(np, "pxclk");
129	if (IS_ERR(clk)) {
130		DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe->id);
131		return PTR_ERR(clk);
132	}
133	pipe->pxlclk = clk;
134
135	/* enum ports */
136	pipe->of_output_links[0] =
137		of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);
138	pipe->of_output_links[1] =
139		of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 1);
140	pipe->of_output_port =
141		of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);
142
143	pipe->dual_link = pipe->of_output_links[0] && pipe->of_output_links[1];
144
145	return 0;
146}
147
148static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)
149{
150	struct platform_device *pdev = to_platform_device(dev);
151	struct device_node *child, *np = dev->of_node;
152	struct komeda_pipeline *pipe;
153	u32 pipe_id = U32_MAX;
154	int ret = -1;
155
156	mdev->irq  = platform_get_irq(pdev, 0);
157	if (mdev->irq < 0) {
158		DRM_ERROR("could not get IRQ number.\n");
159		return mdev->irq;
160	}
161
162	/* Get the optional framebuffer memory resource */
163	ret = of_reserved_mem_device_init(dev);
164	if (ret && ret != -ENODEV)
165		return ret;
166	ret = 0;
167
168	for_each_available_child_of_node(np, child) {
169		if (of_node_name_eq(child, "pipeline")) {
170			of_property_read_u32(child, "reg", &pipe_id);
171			if (pipe_id >= mdev->n_pipelines) {
172				DRM_WARN("Skip the redundant DT node: pipeline-%u.\n",
173					 pipe_id);
174				continue;
175			}
176			mdev->pipelines[pipe_id]->of_node = of_node_get(child);
177		}
178	}
179
180	for (pipe_id = 0; pipe_id < mdev->n_pipelines; pipe_id++) {
181		pipe = mdev->pipelines[pipe_id];
182
183		if (!pipe->of_node) {
184			DRM_ERROR("Pipeline-%d doesn't have a DT node.\n",
185				  pipe->id);
186			return -EINVAL;
187		}
188		ret = komeda_parse_pipe_dt(pipe);
189		if (ret)
190			return ret;
191	}
192
193	return 0;
194}
195
196struct komeda_dev *komeda_dev_create(struct device *dev)
197{
198	struct platform_device *pdev = to_platform_device(dev);
199	komeda_identify_func komeda_identify;
200	struct komeda_dev *mdev;
201	int err = 0;
202
203	komeda_identify = of_device_get_match_data(dev);
204	if (!komeda_identify)
205		return ERR_PTR(-ENODEV);
206
207	mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);
208	if (!mdev)
209		return ERR_PTR(-ENOMEM);
210
211	mutex_init(&mdev->lock);
212
213	mdev->dev = dev;
214	mdev->reg_base = devm_platform_ioremap_resource(pdev, 0);
215	if (IS_ERR(mdev->reg_base)) {
216		DRM_ERROR("Map register space failed.\n");
217		err = PTR_ERR(mdev->reg_base);
218		mdev->reg_base = NULL;
219		goto err_cleanup;
220	}
221
222	mdev->aclk = devm_clk_get(dev, "aclk");
223	if (IS_ERR(mdev->aclk)) {
224		DRM_ERROR("Get engine clk failed.\n");
225		err = PTR_ERR(mdev->aclk);
226		mdev->aclk = NULL;
227		goto err_cleanup;
228	}
229
230	clk_prepare_enable(mdev->aclk);
231
232	mdev->funcs = komeda_identify(mdev->reg_base, &mdev->chip);
233	if (!mdev->funcs) {
234		DRM_ERROR("Failed to identify the HW.\n");
235		err = -ENODEV;
236		goto disable_clk;
237	}
238
239	DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",
240		 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),
241		 MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),
242		 MALIDP_CORE_ID_MINOR(mdev->chip.core_id));
243
244	mdev->funcs->init_format_table(mdev);
245
246	err = mdev->funcs->enum_resources(mdev);
247	if (err) {
248		DRM_ERROR("enumerate display resource failed.\n");
249		goto disable_clk;
250	}
251
252	err = komeda_parse_dt(dev, mdev);
253	if (err) {
254		DRM_ERROR("parse device tree failed.\n");
255		goto disable_clk;
256	}
257
258	err = komeda_assemble_pipelines(mdev);
259	if (err) {
260		DRM_ERROR("assemble display pipelines failed.\n");
261		goto disable_clk;
262	}
263
264	dev->dma_parms = &mdev->dma_parms;
265	dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
266
267	mdev->iommu = iommu_get_domain_for_dev(mdev->dev);
268	if (!mdev->iommu)
269		DRM_INFO("continue without IOMMU support!\n");
270
271	clk_disable_unprepare(mdev->aclk);
272
273	err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);
274	if (err) {
275		DRM_ERROR("create sysfs group failed.\n");
276		goto err_cleanup;
277	}
278
279	mdev->err_verbosity = KOMEDA_DEV_PRINT_ERR_EVENTS;
280
281#ifdef CONFIG_DEBUG_FS
282	komeda_debugfs_init(mdev);
283#endif
284
285	return mdev;
286
287disable_clk:
288	clk_disable_unprepare(mdev->aclk);
289err_cleanup:
290	komeda_dev_destroy(mdev);
291	return ERR_PTR(err);
292}
293
294void komeda_dev_destroy(struct komeda_dev *mdev)
295{
296	struct device *dev = mdev->dev;
297	const struct komeda_dev_funcs *funcs = mdev->funcs;
298	int i;
299
300	sysfs_remove_group(&dev->kobj, &komeda_sysfs_attr_group);
301
302#ifdef CONFIG_DEBUG_FS
303	debugfs_remove_recursive(mdev->debugfs_root);
304#endif
305
306	if (mdev->aclk)
307		clk_prepare_enable(mdev->aclk);
308
309	for (i = 0; i < mdev->n_pipelines; i++) {
310		komeda_pipeline_destroy(mdev, mdev->pipelines[i]);
311		mdev->pipelines[i] = NULL;
312	}
313
314	mdev->n_pipelines = 0;
315
316	of_reserved_mem_device_release(dev);
317
318	if (funcs && funcs->cleanup)
319		funcs->cleanup(mdev);
320
321	if (mdev->reg_base) {
322		devm_iounmap(dev, mdev->reg_base);
323		mdev->reg_base = NULL;
324	}
325
326	if (mdev->aclk) {
327		clk_disable_unprepare(mdev->aclk);
328		devm_clk_put(dev, mdev->aclk);
329		mdev->aclk = NULL;
330	}
331
332	devm_kfree(dev, mdev);
333}
334
335int komeda_dev_resume(struct komeda_dev *mdev)
336{
337	clk_prepare_enable(mdev->aclk);
338
339	mdev->funcs->enable_irq(mdev);
340
341	if (mdev->iommu && mdev->funcs->connect_iommu)
342		if (mdev->funcs->connect_iommu(mdev))
343			DRM_ERROR("connect iommu failed.\n");
344
345	return 0;
346}
347
348int komeda_dev_suspend(struct komeda_dev *mdev)
349{
350	if (mdev->iommu && mdev->funcs->disconnect_iommu)
351		if (mdev->funcs->disconnect_iommu(mdev))
352			DRM_ERROR("disconnect iommu failed.\n");
353
354	mdev->funcs->disable_irq(mdev);
355
356	clk_disable_unprepare(mdev->aclk);
357
358	return 0;
359}