Path: blob/master/drivers/gpu/drm/arm/display/komeda/komeda_dev.c
26519 views
// SPDX-License-Identifier: GPL-2.01/*2* (C) COPYRIGHT 2018 ARM Limited. All rights reserved.3* Author: James.Qian.Wang <[email protected]>4*5*/6#include <linux/io.h>7#include <linux/iommu.h>8#include <linux/of.h>9#include <linux/of_graph.h>10#include <linux/of_reserved_mem.h>11#include <linux/platform_device.h>12#include <linux/pm_runtime.h>13#include <linux/dma-mapping.h>14#include <linux/debugfs.h>15#include <linux/seq_file.h>1617#include <drm/drm_print.h>1819#include "komeda_dev.h"2021static int komeda_register_show(struct seq_file *sf, void *x)22{23struct komeda_dev *mdev = sf->private;24int i;2526seq_puts(sf, "\n====== Komeda register dump =========\n");2728pm_runtime_get_sync(mdev->dev);2930if (mdev->funcs->dump_register)31mdev->funcs->dump_register(mdev, sf);3233for (i = 0; i < mdev->n_pipelines; i++)34komeda_pipeline_dump_register(mdev->pipelines[i], sf);3536pm_runtime_put(mdev->dev);3738return 0;39}4041DEFINE_SHOW_ATTRIBUTE(komeda_register);4243static void komeda_debugfs_init(struct komeda_dev *mdev)44{45if (!debugfs_initialized())46return;4748mdev->debugfs_root = debugfs_create_dir("komeda", NULL);49debugfs_create_file("register", 0444, mdev->debugfs_root,50mdev, &komeda_register_fops);51debugfs_create_x16("err_verbosity", 0664, mdev->debugfs_root,52&mdev->err_verbosity);53}5455static ssize_t56core_id_show(struct device *dev, struct device_attribute *attr, char *buf)57{58struct komeda_dev *mdev = dev_to_mdev(dev);5960return sysfs_emit(buf, "0x%08x\n", mdev->chip.core_id);61}62static DEVICE_ATTR_RO(core_id);6364static ssize_t65config_id_show(struct device *dev, struct device_attribute *attr, char *buf)66{67struct komeda_dev *mdev = dev_to_mdev(dev);68struct komeda_pipeline *pipe = mdev->pipelines[0];69union komeda_config_id config_id;70int i;7172memset(&config_id, 0, sizeof(config_id));7374config_id.max_line_sz = pipe->layers[0]->hsize_in.end;75config_id.n_pipelines = mdev->n_pipelines;76config_id.n_scalers = pipe->n_scalers;77config_id.n_layers = pipe->n_layers;78config_id.n_richs = 0;79for (i = 0; i < pipe->n_layers; i++) {80if (pipe->layers[i]->layer_type == KOMEDA_FMT_RICH_LAYER)81config_id.n_richs++;82}83return sysfs_emit(buf, "0x%08x\n", config_id.value);84}85static DEVICE_ATTR_RO(config_id);8687static ssize_t88aclk_hz_show(struct device *dev, struct device_attribute *attr, char *buf)89{90struct komeda_dev *mdev = dev_to_mdev(dev);9192return sysfs_emit(buf, "%lu\n", clk_get_rate(mdev->aclk));93}94static DEVICE_ATTR_RO(aclk_hz);9596static struct attribute *komeda_sysfs_entries[] = {97&dev_attr_core_id.attr,98&dev_attr_config_id.attr,99&dev_attr_aclk_hz.attr,100NULL,101};102103static struct attribute_group komeda_sysfs_attr_group = {104.attrs = komeda_sysfs_entries,105};106107static int komeda_parse_pipe_dt(struct komeda_pipeline *pipe)108{109struct device_node *np = pipe->of_node;110struct clk *clk;111112clk = of_clk_get_by_name(np, "pxclk");113if (IS_ERR(clk)) {114DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe->id);115return PTR_ERR(clk);116}117pipe->pxlclk = clk;118119/* enum ports */120pipe->of_output_links[0] =121of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0);122pipe->of_output_links[1] =123of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 1);124pipe->of_output_port =125of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT);126127pipe->dual_link = pipe->of_output_links[0] && pipe->of_output_links[1];128129return 0;130}131132static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev)133{134struct platform_device *pdev = to_platform_device(dev);135struct device_node *child, *np = dev->of_node;136struct komeda_pipeline *pipe;137u32 pipe_id = U32_MAX;138int ret = -1;139140mdev->irq = platform_get_irq(pdev, 0);141if (mdev->irq < 0) {142DRM_ERROR("could not get IRQ number.\n");143return mdev->irq;144}145146/* Get the optional framebuffer memory resource */147ret = of_reserved_mem_device_init(dev);148if (ret && ret != -ENODEV)149return ret;150151for_each_available_child_of_node(np, child) {152if (of_node_name_eq(child, "pipeline")) {153of_property_read_u32(child, "reg", &pipe_id);154if (pipe_id >= mdev->n_pipelines) {155DRM_WARN("Skip the redundant DT node: pipeline-%u.\n",156pipe_id);157continue;158}159mdev->pipelines[pipe_id]->of_node = of_node_get(child);160}161}162163for (pipe_id = 0; pipe_id < mdev->n_pipelines; pipe_id++) {164pipe = mdev->pipelines[pipe_id];165166if (!pipe->of_node) {167DRM_ERROR("Pipeline-%d doesn't have a DT node.\n",168pipe->id);169return -EINVAL;170}171ret = komeda_parse_pipe_dt(pipe);172if (ret)173return ret;174}175176return 0;177}178179struct komeda_dev *komeda_dev_create(struct device *dev)180{181struct platform_device *pdev = to_platform_device(dev);182komeda_identify_func komeda_identify;183struct komeda_dev *mdev;184int err = 0;185186komeda_identify = of_device_get_match_data(dev);187if (!komeda_identify)188return ERR_PTR(-ENODEV);189190mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL);191if (!mdev)192return ERR_PTR(-ENOMEM);193194mutex_init(&mdev->lock);195196mdev->dev = dev;197mdev->reg_base = devm_platform_ioremap_resource(pdev, 0);198if (IS_ERR(mdev->reg_base)) {199DRM_ERROR("Map register space failed.\n");200err = PTR_ERR(mdev->reg_base);201mdev->reg_base = NULL;202goto err_cleanup;203}204205mdev->aclk = devm_clk_get(dev, "aclk");206if (IS_ERR(mdev->aclk)) {207DRM_ERROR("Get engine clk failed.\n");208err = PTR_ERR(mdev->aclk);209mdev->aclk = NULL;210goto err_cleanup;211}212213clk_prepare_enable(mdev->aclk);214215mdev->funcs = komeda_identify(mdev->reg_base, &mdev->chip);216if (!mdev->funcs) {217DRM_ERROR("Failed to identify the HW.\n");218err = -ENODEV;219goto disable_clk;220}221222DRM_INFO("Found ARM Mali-D%x version r%dp%d\n",223MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id),224MALIDP_CORE_ID_MAJOR(mdev->chip.core_id),225MALIDP_CORE_ID_MINOR(mdev->chip.core_id));226227mdev->funcs->init_format_table(mdev);228229err = mdev->funcs->enum_resources(mdev);230if (err) {231DRM_ERROR("enumerate display resource failed.\n");232goto disable_clk;233}234235err = komeda_parse_dt(dev, mdev);236if (err) {237DRM_ERROR("parse device tree failed.\n");238goto disable_clk;239}240241err = komeda_assemble_pipelines(mdev);242if (err) {243DRM_ERROR("assemble display pipelines failed.\n");244goto disable_clk;245}246247dma_set_max_seg_size(dev, U32_MAX);248249mdev->iommu = iommu_get_domain_for_dev(mdev->dev);250if (!mdev->iommu)251DRM_INFO("continue without IOMMU support!\n");252253clk_disable_unprepare(mdev->aclk);254255err = sysfs_create_group(&dev->kobj, &komeda_sysfs_attr_group);256if (err) {257DRM_ERROR("create sysfs group failed.\n");258goto err_cleanup;259}260261mdev->err_verbosity = KOMEDA_DEV_PRINT_ERR_EVENTS;262263komeda_debugfs_init(mdev);264265return mdev;266267disable_clk:268clk_disable_unprepare(mdev->aclk);269err_cleanup:270komeda_dev_destroy(mdev);271return ERR_PTR(err);272}273274void komeda_dev_destroy(struct komeda_dev *mdev)275{276struct device *dev = mdev->dev;277const struct komeda_dev_funcs *funcs = mdev->funcs;278int i;279280sysfs_remove_group(&dev->kobj, &komeda_sysfs_attr_group);281282debugfs_remove_recursive(mdev->debugfs_root);283284if (mdev->aclk)285clk_prepare_enable(mdev->aclk);286287for (i = 0; i < mdev->n_pipelines; i++) {288komeda_pipeline_destroy(mdev, mdev->pipelines[i]);289mdev->pipelines[i] = NULL;290}291292mdev->n_pipelines = 0;293294of_reserved_mem_device_release(dev);295296if (funcs && funcs->cleanup)297funcs->cleanup(mdev);298299if (mdev->reg_base) {300devm_iounmap(dev, mdev->reg_base);301mdev->reg_base = NULL;302}303304if (mdev->aclk) {305clk_disable_unprepare(mdev->aclk);306devm_clk_put(dev, mdev->aclk);307mdev->aclk = NULL;308}309310devm_kfree(dev, mdev);311}312313int komeda_dev_resume(struct komeda_dev *mdev)314{315clk_prepare_enable(mdev->aclk);316317mdev->funcs->enable_irq(mdev);318319if (mdev->iommu && mdev->funcs->connect_iommu)320if (mdev->funcs->connect_iommu(mdev))321DRM_ERROR("connect iommu failed.\n");322323return 0;324}325326int komeda_dev_suspend(struct komeda_dev *mdev)327{328if (mdev->iommu && mdev->funcs->disconnect_iommu)329if (mdev->funcs->disconnect_iommu(mdev))330DRM_ERROR("disconnect iommu failed.\n");331332mdev->funcs->disable_irq(mdev);333334clk_disable_unprepare(mdev->aclk);335336return 0;337}338339340