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