1 /* 2 * Copyright (c) 2015, NVIDIA Corporation. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 2 as 6 * published by the Free Software Foundation. 7 */ 8 9 #include <linux/clk.h> 10 #include <linux/host1x.h> 11 #include <linux/iommu.h> 12 #include <linux/module.h> 13 #include <linux/of.h> 14 #include <linux/of_device.h> 15 #include <linux/of_platform.h> 16 #include <linux/platform_device.h> 17 #include <linux/pm_runtime.h> 18 #include <linux/reset.h> 19 20 #include <soc/tegra/pmc.h> 21 22 #include "drm.h" 23 #include "falcon.h" 24 #include "vic.h" 25 26 struct vic_config { 27 const char *firmware; 28 unsigned int version; 29 }; 30 31 struct vic { 32 struct falcon falcon; 33 bool booted; 34 35 void __iomem *regs; 36 struct tegra_drm_client client; 37 struct host1x_channel *channel; 38 struct iommu_domain *domain; 39 struct device *dev; 40 struct clk *clk; 41 42 /* Platform configuration */ 43 const struct vic_config *config; 44 }; 45 46 static inline struct vic *to_vic(struct tegra_drm_client *client) 47 { 48 return container_of(client, struct vic, client); 49 } 50 51 static void vic_writel(struct vic *vic, u32 value, unsigned int offset) 52 { 53 writel(value, vic->regs + offset); 54 } 55 56 static int vic_runtime_resume(struct device *dev) 57 { 58 struct vic *vic = dev_get_drvdata(dev); 59 60 return clk_prepare_enable(vic->clk); 61 } 62 63 static int vic_runtime_suspend(struct device *dev) 64 { 65 struct vic *vic = dev_get_drvdata(dev); 66 67 clk_disable_unprepare(vic->clk); 68 69 vic->booted = false; 70 71 return 0; 72 } 73 74 static int vic_boot(struct vic *vic) 75 { 76 u32 fce_ucode_size, fce_bin_data_offset; 77 void *hdr; 78 int err = 0; 79 80 if (vic->booted) 81 return 0; 82 83 /* setup clockgating registers */ 84 vic_writel(vic, CG_IDLE_CG_DLY_CNT(4) | 85 CG_IDLE_CG_EN | 86 CG_WAKEUP_DLY_CNT(4), 87 NV_PVIC_MISC_PRI_VIC_CG); 88 89 err = falcon_boot(&vic->falcon); 90 if (err < 0) 91 return err; 92 93 hdr = vic->falcon.firmware.vaddr; 94 fce_bin_data_offset = *(u32 *)(hdr + VIC_UCODE_FCE_DATA_OFFSET); 95 hdr = vic->falcon.firmware.vaddr + 96 *(u32 *)(hdr + VIC_UCODE_FCE_HEADER_OFFSET); 97 fce_ucode_size = *(u32 *)(hdr + FCE_UCODE_SIZE_OFFSET); 98 99 falcon_execute_method(&vic->falcon, VIC_SET_APPLICATION_ID, 1); 100 falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_SIZE, 101 fce_ucode_size); 102 falcon_execute_method(&vic->falcon, VIC_SET_FCE_UCODE_OFFSET, 103 (vic->falcon.firmware.paddr + fce_bin_data_offset) 104 >> 8); 105 106 err = falcon_wait_idle(&vic->falcon); 107 if (err < 0) { 108 dev_err(vic->dev, 109 "failed to set application ID and FCE base\n"); 110 return err; 111 } 112 113 vic->booted = true; 114 115 return 0; 116 } 117 118 static void *vic_falcon_alloc(struct falcon *falcon, size_t size, 119 dma_addr_t *iova) 120 { 121 struct tegra_drm *tegra = falcon->data; 122 123 return tegra_drm_alloc(tegra, size, iova); 124 } 125 126 static void vic_falcon_free(struct falcon *falcon, size_t size, 127 dma_addr_t iova, void *va) 128 { 129 struct tegra_drm *tegra = falcon->data; 130 131 return tegra_drm_free(tegra, size, va, iova); 132 } 133 134 static const struct falcon_ops vic_falcon_ops = { 135 .alloc = vic_falcon_alloc, 136 .free = vic_falcon_free 137 }; 138 139 static int vic_init(struct host1x_client *client) 140 { 141 struct tegra_drm_client *drm = host1x_to_drm_client(client); 142 struct iommu_group *group = iommu_group_get(client->dev); 143 struct drm_device *dev = dev_get_drvdata(client->parent); 144 struct tegra_drm *tegra = dev->dev_private; 145 struct vic *vic = to_vic(drm); 146 int err; 147 148 if (group && tegra->domain) { 149 err = iommu_attach_group(tegra->domain, group); 150 if (err < 0) { 151 dev_err(vic->dev, "failed to attach to domain: %d\n", 152 err); 153 return err; 154 } 155 156 vic->domain = tegra->domain; 157 } 158 159 if (!vic->falcon.data) { 160 vic->falcon.data = tegra; 161 err = falcon_load_firmware(&vic->falcon); 162 if (err < 0) 163 goto detach; 164 } 165 166 vic->channel = host1x_channel_request(client->dev); 167 if (!vic->channel) { 168 err = -ENOMEM; 169 goto detach; 170 } 171 172 client->syncpts[0] = host1x_syncpt_request(client, 0); 173 if (!client->syncpts[0]) { 174 err = -ENOMEM; 175 goto free_channel; 176 } 177 178 err = tegra_drm_register_client(tegra, drm); 179 if (err < 0) 180 goto free_syncpt; 181 182 return 0; 183 184 free_syncpt: 185 host1x_syncpt_free(client->syncpts[0]); 186 free_channel: 187 host1x_channel_put(vic->channel); 188 detach: 189 if (group && tegra->domain) 190 iommu_detach_group(tegra->domain, group); 191 192 return err; 193 } 194 195 static int vic_exit(struct host1x_client *client) 196 { 197 struct tegra_drm_client *drm = host1x_to_drm_client(client); 198 struct iommu_group *group = iommu_group_get(client->dev); 199 struct drm_device *dev = dev_get_drvdata(client->parent); 200 struct tegra_drm *tegra = dev->dev_private; 201 struct vic *vic = to_vic(drm); 202 int err; 203 204 err = tegra_drm_unregister_client(tegra, drm); 205 if (err < 0) 206 return err; 207 208 host1x_syncpt_free(client->syncpts[0]); 209 host1x_channel_put(vic->channel); 210 211 if (vic->domain) { 212 iommu_detach_group(vic->domain, group); 213 vic->domain = NULL; 214 } 215 216 return 0; 217 } 218 219 static const struct host1x_client_ops vic_client_ops = { 220 .init = vic_init, 221 .exit = vic_exit, 222 }; 223 224 static int vic_open_channel(struct tegra_drm_client *client, 225 struct tegra_drm_context *context) 226 { 227 struct vic *vic = to_vic(client); 228 int err; 229 230 err = pm_runtime_get_sync(vic->dev); 231 if (err < 0) 232 return err; 233 234 err = vic_boot(vic); 235 if (err < 0) { 236 pm_runtime_put(vic->dev); 237 return err; 238 } 239 240 context->channel = host1x_channel_get(vic->channel); 241 if (!context->channel) { 242 pm_runtime_put(vic->dev); 243 return -ENOMEM; 244 } 245 246 return 0; 247 } 248 249 static void vic_close_channel(struct tegra_drm_context *context) 250 { 251 struct vic *vic = to_vic(context->client); 252 253 host1x_channel_put(context->channel); 254 255 pm_runtime_put(vic->dev); 256 } 257 258 static const struct tegra_drm_client_ops vic_ops = { 259 .open_channel = vic_open_channel, 260 .close_channel = vic_close_channel, 261 .submit = tegra_drm_submit, 262 }; 263 264 #define NVIDIA_TEGRA_124_VIC_FIRMWARE "nvidia/tegra124/vic03_ucode.bin" 265 266 static const struct vic_config vic_t124_config = { 267 .firmware = NVIDIA_TEGRA_124_VIC_FIRMWARE, 268 .version = 0x40, 269 }; 270 271 #define NVIDIA_TEGRA_210_VIC_FIRMWARE "nvidia/tegra210/vic04_ucode.bin" 272 273 static const struct vic_config vic_t210_config = { 274 .firmware = NVIDIA_TEGRA_210_VIC_FIRMWARE, 275 .version = 0x21, 276 }; 277 278 #define NVIDIA_TEGRA_186_VIC_FIRMWARE "nvidia/tegra186/vic04_ucode.bin" 279 280 static const struct vic_config vic_t186_config = { 281 .firmware = NVIDIA_TEGRA_186_VIC_FIRMWARE, 282 .version = 0x18, 283 }; 284 285 static const struct of_device_id vic_match[] = { 286 { .compatible = "nvidia,tegra124-vic", .data = &vic_t124_config }, 287 { .compatible = "nvidia,tegra210-vic", .data = &vic_t210_config }, 288 { .compatible = "nvidia,tegra186-vic", .data = &vic_t186_config }, 289 { }, 290 }; 291 292 static int vic_probe(struct platform_device *pdev) 293 { 294 struct device *dev = &pdev->dev; 295 struct host1x_syncpt **syncpts; 296 struct resource *regs; 297 struct vic *vic; 298 int err; 299 300 vic = devm_kzalloc(dev, sizeof(*vic), GFP_KERNEL); 301 if (!vic) 302 return -ENOMEM; 303 304 vic->config = of_device_get_match_data(dev); 305 306 syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); 307 if (!syncpts) 308 return -ENOMEM; 309 310 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); 311 if (!regs) { 312 dev_err(&pdev->dev, "failed to get registers\n"); 313 return -ENXIO; 314 } 315 316 vic->regs = devm_ioremap_resource(dev, regs); 317 if (IS_ERR(vic->regs)) 318 return PTR_ERR(vic->regs); 319 320 vic->clk = devm_clk_get(dev, NULL); 321 if (IS_ERR(vic->clk)) { 322 dev_err(&pdev->dev, "failed to get clock\n"); 323 return PTR_ERR(vic->clk); 324 } 325 326 vic->falcon.dev = dev; 327 vic->falcon.regs = vic->regs; 328 vic->falcon.ops = &vic_falcon_ops; 329 330 err = falcon_init(&vic->falcon); 331 if (err < 0) 332 return err; 333 334 err = falcon_read_firmware(&vic->falcon, vic->config->firmware); 335 if (err < 0) 336 goto exit_falcon; 337 338 platform_set_drvdata(pdev, vic); 339 340 INIT_LIST_HEAD(&vic->client.base.list); 341 vic->client.base.ops = &vic_client_ops; 342 vic->client.base.dev = dev; 343 vic->client.base.class = HOST1X_CLASS_VIC; 344 vic->client.base.syncpts = syncpts; 345 vic->client.base.num_syncpts = 1; 346 vic->dev = dev; 347 348 INIT_LIST_HEAD(&vic->client.list); 349 vic->client.version = vic->config->version; 350 vic->client.ops = &vic_ops; 351 352 err = host1x_client_register(&vic->client.base); 353 if (err < 0) { 354 dev_err(dev, "failed to register host1x client: %d\n", err); 355 platform_set_drvdata(pdev, NULL); 356 goto exit_falcon; 357 } 358 359 pm_runtime_enable(&pdev->dev); 360 if (!pm_runtime_enabled(&pdev->dev)) { 361 err = vic_runtime_resume(&pdev->dev); 362 if (err < 0) 363 goto unregister_client; 364 } 365 366 return 0; 367 368 unregister_client: 369 host1x_client_unregister(&vic->client.base); 370 exit_falcon: 371 falcon_exit(&vic->falcon); 372 373 return err; 374 } 375 376 static int vic_remove(struct platform_device *pdev) 377 { 378 struct vic *vic = platform_get_drvdata(pdev); 379 int err; 380 381 err = host1x_client_unregister(&vic->client.base); 382 if (err < 0) { 383 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 384 err); 385 return err; 386 } 387 388 if (pm_runtime_enabled(&pdev->dev)) 389 pm_runtime_disable(&pdev->dev); 390 else 391 vic_runtime_suspend(&pdev->dev); 392 393 falcon_exit(&vic->falcon); 394 395 return 0; 396 } 397 398 static const struct dev_pm_ops vic_pm_ops = { 399 SET_RUNTIME_PM_OPS(vic_runtime_suspend, vic_runtime_resume, NULL) 400 }; 401 402 struct platform_driver tegra_vic_driver = { 403 .driver = { 404 .name = "tegra-vic", 405 .of_match_table = vic_match, 406 .pm = &vic_pm_ops 407 }, 408 .probe = vic_probe, 409 .remove = vic_remove, 410 }; 411 412 #if IS_ENABLED(CONFIG_ARCH_TEGRA_124_SOC) 413 MODULE_FIRMWARE(NVIDIA_TEGRA_124_VIC_FIRMWARE); 414 #endif 415 #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) 416 MODULE_FIRMWARE(NVIDIA_TEGRA_210_VIC_FIRMWARE); 417 #endif 418 #if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) 419 MODULE_FIRMWARE(NVIDIA_TEGRA_186_VIC_FIRMWARE); 420 #endif 421