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