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/platform_device.h> 8 #include <linux/of_device.h> 9 #include <linux/of_graph.h> 10 #include "komeda_dev.h" 11 12 static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) 13 { 14 struct komeda_pipeline *pipe; 15 struct clk *clk; 16 u32 pipe_id; 17 int ret = 0; 18 19 ret = of_property_read_u32(np, "reg", &pipe_id); 20 if (ret != 0 || pipe_id >= mdev->n_pipelines) 21 return -EINVAL; 22 23 pipe = mdev->pipelines[pipe_id]; 24 25 clk = of_clk_get_by_name(np, "aclk"); 26 if (IS_ERR(clk)) { 27 DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id); 28 return PTR_ERR(clk); 29 } 30 pipe->aclk = clk; 31 32 clk = of_clk_get_by_name(np, "pxclk"); 33 if (IS_ERR(clk)) { 34 DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id); 35 return PTR_ERR(clk); 36 } 37 pipe->pxlclk = clk; 38 39 /* enum ports */ 40 pipe->of_output_dev = 41 of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0); 42 pipe->of_output_port = 43 of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT); 44 45 pipe->of_node = np; 46 47 return 0; 48 } 49 50 static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev) 51 { 52 struct device_node *child, *np = dev->of_node; 53 struct clk *clk; 54 int ret; 55 56 clk = devm_clk_get(dev, "mclk"); 57 if (IS_ERR(clk)) 58 return PTR_ERR(clk); 59 60 mdev->mclk = clk; 61 62 for_each_available_child_of_node(np, child) { 63 if (of_node_cmp(child->name, "pipeline") == 0) { 64 ret = komeda_parse_pipe_dt(mdev, child); 65 if (ret) { 66 DRM_ERROR("parse pipeline dt error!\n"); 67 of_node_put(child); 68 break; 69 } 70 } 71 } 72 73 return ret; 74 } 75 76 struct komeda_dev *komeda_dev_create(struct device *dev) 77 { 78 struct platform_device *pdev = to_platform_device(dev); 79 const struct komeda_product_data *product; 80 struct komeda_dev *mdev; 81 struct resource *io_res; 82 int err = 0; 83 84 product = of_device_get_match_data(dev); 85 if (!product) 86 return ERR_PTR(-ENODEV); 87 88 io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 89 if (!io_res) { 90 DRM_ERROR("No registers defined.\n"); 91 return ERR_PTR(-ENODEV); 92 } 93 94 mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL); 95 if (!mdev) 96 return ERR_PTR(-ENOMEM); 97 98 mdev->dev = dev; 99 mdev->reg_base = devm_ioremap_resource(dev, io_res); 100 if (IS_ERR(mdev->reg_base)) { 101 DRM_ERROR("Map register space failed.\n"); 102 err = PTR_ERR(mdev->reg_base); 103 mdev->reg_base = NULL; 104 goto err_cleanup; 105 } 106 107 mdev->pclk = devm_clk_get(dev, "pclk"); 108 if (IS_ERR(mdev->pclk)) { 109 DRM_ERROR("Get APB clk failed.\n"); 110 err = PTR_ERR(mdev->pclk); 111 mdev->pclk = NULL; 112 goto err_cleanup; 113 } 114 115 /* Enable APB clock to access the registers */ 116 clk_prepare_enable(mdev->pclk); 117 118 mdev->funcs = product->identify(mdev->reg_base, &mdev->chip); 119 if (!komeda_product_match(mdev, product->product_id)) { 120 DRM_ERROR("DT configured %x mismatch with real HW %x.\n", 121 product->product_id, 122 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id)); 123 err = -ENODEV; 124 goto err_cleanup; 125 } 126 127 DRM_INFO("Found ARM Mali-D%x version r%dp%d\n", 128 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id), 129 MALIDP_CORE_ID_MAJOR(mdev->chip.core_id), 130 MALIDP_CORE_ID_MINOR(mdev->chip.core_id)); 131 132 mdev->funcs->init_format_table(mdev); 133 134 err = mdev->funcs->enum_resources(mdev); 135 if (err) { 136 DRM_ERROR("enumerate display resource failed.\n"); 137 goto err_cleanup; 138 } 139 140 err = komeda_parse_dt(dev, mdev); 141 if (err) { 142 DRM_ERROR("parse device tree failed.\n"); 143 goto err_cleanup; 144 } 145 146 return mdev; 147 148 err_cleanup: 149 komeda_dev_destroy(mdev); 150 return ERR_PTR(err); 151 } 152 153 void komeda_dev_destroy(struct komeda_dev *mdev) 154 { 155 struct device *dev = mdev->dev; 156 struct komeda_dev_funcs *funcs = mdev->funcs; 157 int i; 158 159 for (i = 0; i < mdev->n_pipelines; i++) { 160 komeda_pipeline_destroy(mdev, mdev->pipelines[i]); 161 mdev->pipelines[i] = NULL; 162 } 163 164 mdev->n_pipelines = 0; 165 166 if (funcs && funcs->cleanup) 167 funcs->cleanup(mdev); 168 169 if (mdev->reg_base) { 170 devm_iounmap(dev, mdev->reg_base); 171 mdev->reg_base = NULL; 172 } 173 174 if (mdev->mclk) { 175 devm_clk_put(dev, mdev->mclk); 176 mdev->mclk = NULL; 177 } 178 179 if (mdev->pclk) { 180 clk_disable_unprepare(mdev->pclk); 181 devm_clk_put(dev, mdev->pclk); 182 mdev->pclk = NULL; 183 } 184 185 devm_kfree(dev, mdev); 186 } 187