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/of_device.h> 9 #include <linux/of_graph.h> 10 #include <linux/platform_device.h> 11 #ifdef CONFIG_DEBUG_FS 12 #include <linux/debugfs.h> 13 #include <linux/seq_file.h> 14 #endif 15 16 #include <drm/drm_print.h> 17 18 #include "komeda_dev.h" 19 20 static int komeda_register_show(struct seq_file *sf, void *x) 21 { 22 struct komeda_dev *mdev = sf->private; 23 int i; 24 25 if (mdev->funcs->dump_register) 26 mdev->funcs->dump_register(mdev, sf); 27 28 for (i = 0; i < mdev->n_pipelines; i++) 29 komeda_pipeline_dump_register(mdev->pipelines[i], sf); 30 31 return 0; 32 } 33 34 static int komeda_register_open(struct inode *inode, struct file *filp) 35 { 36 return single_open(filp, komeda_register_show, inode->i_private); 37 } 38 39 static const struct file_operations komeda_register_fops = { 40 .owner = THIS_MODULE, 41 .open = komeda_register_open, 42 .read = seq_read, 43 .llseek = seq_lseek, 44 .release = single_release, 45 }; 46 47 #ifdef CONFIG_DEBUG_FS 48 static void komeda_debugfs_init(struct komeda_dev *mdev) 49 { 50 if (!debugfs_initialized()) 51 return; 52 53 mdev->debugfs_root = debugfs_create_dir("komeda", NULL); 54 if (IS_ERR_OR_NULL(mdev->debugfs_root)) 55 return; 56 57 debugfs_create_file("register", 0444, mdev->debugfs_root, 58 mdev, &komeda_register_fops); 59 } 60 #endif 61 62 static int komeda_parse_pipe_dt(struct komeda_dev *mdev, struct device_node *np) 63 { 64 struct komeda_pipeline *pipe; 65 struct clk *clk; 66 u32 pipe_id; 67 int ret = 0; 68 69 ret = of_property_read_u32(np, "reg", &pipe_id); 70 if (ret != 0 || pipe_id >= mdev->n_pipelines) 71 return -EINVAL; 72 73 pipe = mdev->pipelines[pipe_id]; 74 75 clk = of_clk_get_by_name(np, "aclk"); 76 if (IS_ERR(clk)) { 77 DRM_ERROR("get aclk for pipeline %d failed!\n", pipe_id); 78 return PTR_ERR(clk); 79 } 80 pipe->aclk = clk; 81 82 clk = of_clk_get_by_name(np, "pxclk"); 83 if (IS_ERR(clk)) { 84 DRM_ERROR("get pxclk for pipeline %d failed!\n", pipe_id); 85 return PTR_ERR(clk); 86 } 87 pipe->pxlclk = clk; 88 89 /* enum ports */ 90 pipe->of_output_dev = 91 of_graph_get_remote_node(np, KOMEDA_OF_PORT_OUTPUT, 0); 92 pipe->of_output_port = 93 of_graph_get_port_by_id(np, KOMEDA_OF_PORT_OUTPUT); 94 95 pipe->of_node = np; 96 97 return 0; 98 } 99 100 static int komeda_parse_dt(struct device *dev, struct komeda_dev *mdev) 101 { 102 struct platform_device *pdev = to_platform_device(dev); 103 struct device_node *child, *np = dev->of_node; 104 struct clk *clk; 105 int ret; 106 107 clk = devm_clk_get(dev, "mclk"); 108 if (IS_ERR(clk)) 109 return PTR_ERR(clk); 110 111 mdev->mclk = clk; 112 mdev->irq = platform_get_irq(pdev, 0); 113 if (mdev->irq < 0) { 114 DRM_ERROR("could not get IRQ number.\n"); 115 return mdev->irq; 116 } 117 118 for_each_available_child_of_node(np, child) { 119 if (of_node_cmp(child->name, "pipeline") == 0) { 120 ret = komeda_parse_pipe_dt(mdev, child); 121 if (ret) { 122 DRM_ERROR("parse pipeline dt error!\n"); 123 of_node_put(child); 124 break; 125 } 126 } 127 } 128 129 return ret; 130 } 131 132 struct komeda_dev *komeda_dev_create(struct device *dev) 133 { 134 struct platform_device *pdev = to_platform_device(dev); 135 const struct komeda_product_data *product; 136 struct komeda_dev *mdev; 137 struct resource *io_res; 138 int err = 0; 139 140 product = of_device_get_match_data(dev); 141 if (!product) 142 return ERR_PTR(-ENODEV); 143 144 io_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 145 if (!io_res) { 146 DRM_ERROR("No registers defined.\n"); 147 return ERR_PTR(-ENODEV); 148 } 149 150 mdev = devm_kzalloc(dev, sizeof(*mdev), GFP_KERNEL); 151 if (!mdev) 152 return ERR_PTR(-ENOMEM); 153 154 mutex_init(&mdev->lock); 155 156 mdev->dev = dev; 157 mdev->reg_base = devm_ioremap_resource(dev, io_res); 158 if (IS_ERR(mdev->reg_base)) { 159 DRM_ERROR("Map register space failed.\n"); 160 err = PTR_ERR(mdev->reg_base); 161 mdev->reg_base = NULL; 162 goto err_cleanup; 163 } 164 165 mdev->pclk = devm_clk_get(dev, "pclk"); 166 if (IS_ERR(mdev->pclk)) { 167 DRM_ERROR("Get APB clk failed.\n"); 168 err = PTR_ERR(mdev->pclk); 169 mdev->pclk = NULL; 170 goto err_cleanup; 171 } 172 173 /* Enable APB clock to access the registers */ 174 clk_prepare_enable(mdev->pclk); 175 176 mdev->funcs = product->identify(mdev->reg_base, &mdev->chip); 177 if (!komeda_product_match(mdev, product->product_id)) { 178 DRM_ERROR("DT configured %x mismatch with real HW %x.\n", 179 product->product_id, 180 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id)); 181 err = -ENODEV; 182 goto err_cleanup; 183 } 184 185 DRM_INFO("Found ARM Mali-D%x version r%dp%d\n", 186 MALIDP_CORE_ID_PRODUCT_ID(mdev->chip.core_id), 187 MALIDP_CORE_ID_MAJOR(mdev->chip.core_id), 188 MALIDP_CORE_ID_MINOR(mdev->chip.core_id)); 189 190 mdev->funcs->init_format_table(mdev); 191 192 err = mdev->funcs->enum_resources(mdev); 193 if (err) { 194 DRM_ERROR("enumerate display resource failed.\n"); 195 goto err_cleanup; 196 } 197 198 err = komeda_parse_dt(dev, mdev); 199 if (err) { 200 DRM_ERROR("parse device tree failed.\n"); 201 goto err_cleanup; 202 } 203 204 err = komeda_assemble_pipelines(mdev); 205 if (err) { 206 DRM_ERROR("assemble display pipelines failed.\n"); 207 goto err_cleanup; 208 } 209 210 #ifdef CONFIG_DEBUG_FS 211 komeda_debugfs_init(mdev); 212 #endif 213 214 return mdev; 215 216 err_cleanup: 217 komeda_dev_destroy(mdev); 218 return ERR_PTR(err); 219 } 220 221 void komeda_dev_destroy(struct komeda_dev *mdev) 222 { 223 struct device *dev = mdev->dev; 224 struct komeda_dev_funcs *funcs = mdev->funcs; 225 int i; 226 227 #ifdef CONFIG_DEBUG_FS 228 debugfs_remove_recursive(mdev->debugfs_root); 229 #endif 230 231 for (i = 0; i < mdev->n_pipelines; i++) { 232 komeda_pipeline_destroy(mdev, mdev->pipelines[i]); 233 mdev->pipelines[i] = NULL; 234 } 235 236 mdev->n_pipelines = 0; 237 238 if (funcs && funcs->cleanup) 239 funcs->cleanup(mdev); 240 241 if (mdev->reg_base) { 242 devm_iounmap(dev, mdev->reg_base); 243 mdev->reg_base = NULL; 244 } 245 246 if (mdev->mclk) { 247 devm_clk_put(dev, mdev->mclk); 248 mdev->mclk = NULL; 249 } 250 251 if (mdev->pclk) { 252 clk_disable_unprepare(mdev->pclk); 253 devm_clk_put(dev, mdev->pclk); 254 mdev->pclk = NULL; 255 } 256 257 devm_kfree(dev, mdev); 258 } 259