1 /* 2 * Copyright (C) 2013-2014 Red Hat 3 * Author: Rob Clark <robdclark@gmail.com> 4 * 5 * Copyright (c) 2014 The Linux Foundation. All rights reserved. 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 as published by 9 * the Free Software Foundation. 10 * 11 * This program is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 * more details. 15 * 16 * You should have received a copy of the GNU General Public License along with 17 * this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "adreno_gpu.h" 21 22 #if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF) 23 # include <mach/kgsl.h> 24 #endif 25 26 #define ANY_ID 0xff 27 28 bool hang_debug = false; 29 MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)"); 30 module_param_named(hang_debug, hang_debug, bool, 0600); 31 32 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev); 33 struct msm_gpu *a4xx_gpu_init(struct drm_device *dev); 34 35 static const struct adreno_info gpulist[] = { 36 { 37 .rev = ADRENO_REV(3, 0, 5, ANY_ID), 38 .revn = 305, 39 .name = "A305", 40 .pm4fw = "a300_pm4.fw", 41 .pfpfw = "a300_pfp.fw", 42 .gmem = SZ_256K, 43 .init = a3xx_gpu_init, 44 }, { 45 .rev = ADRENO_REV(3, 2, ANY_ID, ANY_ID), 46 .revn = 320, 47 .name = "A320", 48 .pm4fw = "a300_pm4.fw", 49 .pfpfw = "a300_pfp.fw", 50 .gmem = SZ_512K, 51 .init = a3xx_gpu_init, 52 }, { 53 .rev = ADRENO_REV(3, 3, 0, ANY_ID), 54 .revn = 330, 55 .name = "A330", 56 .pm4fw = "a330_pm4.fw", 57 .pfpfw = "a330_pfp.fw", 58 .gmem = SZ_1M, 59 .init = a3xx_gpu_init, 60 }, { 61 .rev = ADRENO_REV(4, 2, 0, ANY_ID), 62 .revn = 420, 63 .name = "A420", 64 .pm4fw = "a420_pm4.fw", 65 .pfpfw = "a420_pfp.fw", 66 .gmem = (SZ_1M + SZ_512K), 67 .init = a4xx_gpu_init, 68 }, 69 }; 70 71 MODULE_FIRMWARE("a300_pm4.fw"); 72 MODULE_FIRMWARE("a300_pfp.fw"); 73 MODULE_FIRMWARE("a330_pm4.fw"); 74 MODULE_FIRMWARE("a330_pfp.fw"); 75 MODULE_FIRMWARE("a420_pm4.fw"); 76 MODULE_FIRMWARE("a420_pfp.fw"); 77 78 static inline bool _rev_match(uint8_t entry, uint8_t id) 79 { 80 return (entry == ANY_ID) || (entry == id); 81 } 82 83 const struct adreno_info *adreno_info(struct adreno_rev rev) 84 { 85 int i; 86 87 /* identify gpu: */ 88 for (i = 0; i < ARRAY_SIZE(gpulist); i++) { 89 const struct adreno_info *info = &gpulist[i]; 90 if (_rev_match(info->rev.core, rev.core) && 91 _rev_match(info->rev.major, rev.major) && 92 _rev_match(info->rev.minor, rev.minor) && 93 _rev_match(info->rev.patchid, rev.patchid)) 94 return info; 95 } 96 97 return NULL; 98 } 99 100 struct msm_gpu *adreno_load_gpu(struct drm_device *dev) 101 { 102 struct msm_drm_private *priv = dev->dev_private; 103 struct platform_device *pdev = priv->gpu_pdev; 104 struct adreno_platform_config *config; 105 struct adreno_rev rev; 106 const struct adreno_info *info; 107 struct msm_gpu *gpu = NULL; 108 109 if (!pdev) { 110 dev_err(dev->dev, "no adreno device\n"); 111 return NULL; 112 } 113 114 config = pdev->dev.platform_data; 115 rev = config->rev; 116 info = adreno_info(config->rev); 117 118 if (!info) { 119 dev_warn(dev->dev, "Unknown GPU revision: %u.%u.%u.%u\n", 120 rev.core, rev.major, rev.minor, rev.patchid); 121 return NULL; 122 } 123 124 DBG("Found GPU: %u.%u.%u.%u", rev.core, rev.major, 125 rev.minor, rev.patchid); 126 127 gpu = info->init(dev); 128 if (IS_ERR(gpu)) { 129 dev_warn(dev->dev, "failed to load adreno gpu\n"); 130 gpu = NULL; 131 /* not fatal */ 132 } 133 134 if (gpu) { 135 int ret; 136 mutex_lock(&dev->struct_mutex); 137 gpu->funcs->pm_resume(gpu); 138 mutex_unlock(&dev->struct_mutex); 139 ret = gpu->funcs->hw_init(gpu); 140 if (ret) { 141 dev_err(dev->dev, "gpu hw init failed: %d\n", ret); 142 gpu->funcs->destroy(gpu); 143 gpu = NULL; 144 } else { 145 /* give inactive pm a chance to kick in: */ 146 msm_gpu_retire(gpu); 147 } 148 } 149 150 return gpu; 151 } 152 153 static void set_gpu_pdev(struct drm_device *dev, 154 struct platform_device *pdev) 155 { 156 struct msm_drm_private *priv = dev->dev_private; 157 priv->gpu_pdev = pdev; 158 } 159 160 static int adreno_bind(struct device *dev, struct device *master, void *data) 161 { 162 static struct adreno_platform_config config = {}; 163 #ifdef CONFIG_OF 164 struct device_node *child, *node = dev->of_node; 165 u32 val; 166 int ret; 167 168 ret = of_property_read_u32(node, "qcom,chipid", &val); 169 if (ret) { 170 dev_err(dev, "could not find chipid: %d\n", ret); 171 return ret; 172 } 173 174 config.rev = ADRENO_REV((val >> 24) & 0xff, 175 (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); 176 177 /* find clock rates: */ 178 config.fast_rate = 0; 179 config.slow_rate = ~0; 180 for_each_child_of_node(node, child) { 181 if (of_device_is_compatible(child, "qcom,gpu-pwrlevels")) { 182 struct device_node *pwrlvl; 183 for_each_child_of_node(child, pwrlvl) { 184 ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val); 185 if (ret) { 186 dev_err(dev, "could not find gpu-freq: %d\n", ret); 187 return ret; 188 } 189 config.fast_rate = max(config.fast_rate, val); 190 config.slow_rate = min(config.slow_rate, val); 191 } 192 } 193 } 194 195 if (!config.fast_rate) { 196 dev_err(dev, "could not find clk rates\n"); 197 return -ENXIO; 198 } 199 200 #else 201 struct kgsl_device_platform_data *pdata = dev->platform_data; 202 uint32_t version = socinfo_get_version(); 203 if (cpu_is_apq8064ab()) { 204 config.fast_rate = 450000000; 205 config.slow_rate = 27000000; 206 config.bus_freq = 4; 207 config.rev = ADRENO_REV(3, 2, 1, 0); 208 } else if (cpu_is_apq8064()) { 209 config.fast_rate = 400000000; 210 config.slow_rate = 27000000; 211 config.bus_freq = 4; 212 213 if (SOCINFO_VERSION_MAJOR(version) == 2) 214 config.rev = ADRENO_REV(3, 2, 0, 2); 215 else if ((SOCINFO_VERSION_MAJOR(version) == 1) && 216 (SOCINFO_VERSION_MINOR(version) == 1)) 217 config.rev = ADRENO_REV(3, 2, 0, 1); 218 else 219 config.rev = ADRENO_REV(3, 2, 0, 0); 220 221 } else if (cpu_is_msm8960ab()) { 222 config.fast_rate = 400000000; 223 config.slow_rate = 320000000; 224 config.bus_freq = 4; 225 226 if (SOCINFO_VERSION_MINOR(version) == 0) 227 config.rev = ADRENO_REV(3, 2, 1, 0); 228 else 229 config.rev = ADRENO_REV(3, 2, 1, 1); 230 231 } else if (cpu_is_msm8930()) { 232 config.fast_rate = 400000000; 233 config.slow_rate = 27000000; 234 config.bus_freq = 3; 235 236 if ((SOCINFO_VERSION_MAJOR(version) == 1) && 237 (SOCINFO_VERSION_MINOR(version) == 2)) 238 config.rev = ADRENO_REV(3, 0, 5, 2); 239 else 240 config.rev = ADRENO_REV(3, 0, 5, 0); 241 242 } 243 # ifdef CONFIG_MSM_BUS_SCALING 244 config.bus_scale_table = pdata->bus_scale_table; 245 # endif 246 #endif 247 dev->platform_data = &config; 248 set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev)); 249 return 0; 250 } 251 252 static void adreno_unbind(struct device *dev, struct device *master, 253 void *data) 254 { 255 set_gpu_pdev(dev_get_drvdata(master), NULL); 256 } 257 258 static const struct component_ops a3xx_ops = { 259 .bind = adreno_bind, 260 .unbind = adreno_unbind, 261 }; 262 263 static int adreno_probe(struct platform_device *pdev) 264 { 265 return component_add(&pdev->dev, &a3xx_ops); 266 } 267 268 static int adreno_remove(struct platform_device *pdev) 269 { 270 component_del(&pdev->dev, &a3xx_ops); 271 return 0; 272 } 273 274 static const struct of_device_id dt_match[] = { 275 { .compatible = "qcom,adreno-3xx" }, 276 /* for backwards compat w/ downstream kgsl DT files: */ 277 { .compatible = "qcom,kgsl-3d0" }, 278 {} 279 }; 280 281 static struct platform_driver adreno_driver = { 282 .probe = adreno_probe, 283 .remove = adreno_remove, 284 .driver = { 285 .name = "adreno", 286 .of_match_table = dt_match, 287 }, 288 }; 289 290 void __init adreno_register(void) 291 { 292 platform_driver_register(&adreno_driver); 293 } 294 295 void __exit adreno_unregister(void) 296 { 297 platform_driver_unregister(&adreno_driver); 298 } 299