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