1 /* 2 * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 * DEALINGS IN THE SOFTWARE. 21 */ 22 23 #include <linux/clk.h> 24 #include <linux/io.h> 25 #include <linux/module.h> 26 #include <linux/platform_device.h> 27 #include <linux/of.h> 28 #include <linux/reset.h> 29 #include <linux/regulator/consumer.h> 30 #include <soc/tegra/fuse.h> 31 #include <soc/tegra/pmc.h> 32 33 #include "nouveau_drm.h" 34 #include "nouveau_platform.h" 35 36 static int nouveau_platform_power_up(struct nouveau_platform_gpu *gpu) 37 { 38 int err; 39 40 err = regulator_enable(gpu->vdd); 41 if (err) 42 goto err_power; 43 44 err = clk_prepare_enable(gpu->clk); 45 if (err) 46 goto err_clk; 47 err = clk_prepare_enable(gpu->clk_pwr); 48 if (err) 49 goto err_clk_pwr; 50 clk_set_rate(gpu->clk_pwr, 204000000); 51 udelay(10); 52 53 reset_control_assert(gpu->rst); 54 udelay(10); 55 56 err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); 57 if (err) 58 goto err_clamp; 59 udelay(10); 60 61 reset_control_deassert(gpu->rst); 62 udelay(10); 63 64 return 0; 65 66 err_clamp: 67 clk_disable_unprepare(gpu->clk_pwr); 68 err_clk_pwr: 69 clk_disable_unprepare(gpu->clk); 70 err_clk: 71 regulator_disable(gpu->vdd); 72 err_power: 73 return err; 74 } 75 76 static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu) 77 { 78 int err; 79 80 reset_control_assert(gpu->rst); 81 udelay(10); 82 83 clk_disable_unprepare(gpu->clk_pwr); 84 clk_disable_unprepare(gpu->clk); 85 udelay(10); 86 87 err = regulator_disable(gpu->vdd); 88 if (err) 89 return err; 90 91 return 0; 92 } 93 94 static int nouveau_platform_probe(struct platform_device *pdev) 95 { 96 struct nouveau_platform_gpu *gpu; 97 struct nouveau_platform_device *device; 98 struct drm_device *drm; 99 int err; 100 101 gpu = devm_kzalloc(&pdev->dev, sizeof(*gpu), GFP_KERNEL); 102 if (!gpu) 103 return -ENOMEM; 104 105 gpu->vdd = devm_regulator_get(&pdev->dev, "vdd"); 106 if (IS_ERR(gpu->vdd)) 107 return PTR_ERR(gpu->vdd); 108 109 gpu->rst = devm_reset_control_get(&pdev->dev, "gpu"); 110 if (IS_ERR(gpu->rst)) 111 return PTR_ERR(gpu->rst); 112 113 gpu->clk = devm_clk_get(&pdev->dev, "gpu"); 114 if (IS_ERR(gpu->clk)) 115 return PTR_ERR(gpu->clk); 116 117 gpu->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); 118 if (IS_ERR(gpu->clk_pwr)) 119 return PTR_ERR(gpu->clk_pwr); 120 121 err = nouveau_platform_power_up(gpu); 122 if (err) 123 return err; 124 125 drm = nouveau_platform_device_create(pdev, &device); 126 if (IS_ERR(drm)) { 127 err = PTR_ERR(drm); 128 goto power_down; 129 } 130 131 device->gpu = gpu; 132 device->gpu_speedo = tegra_sku_info.gpu_speedo_value; 133 134 err = drm_dev_register(drm, 0); 135 if (err < 0) 136 goto err_unref; 137 138 return 0; 139 140 err_unref: 141 drm_dev_unref(drm); 142 143 return 0; 144 145 power_down: 146 nouveau_platform_power_down(gpu); 147 148 return err; 149 } 150 151 static int nouveau_platform_remove(struct platform_device *pdev) 152 { 153 struct drm_device *drm_dev = platform_get_drvdata(pdev); 154 struct nouveau_drm *drm = nouveau_drm(drm_dev); 155 struct nvkm_device *device = nvxx_device(&drm->device); 156 struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu; 157 158 nouveau_drm_device_remove(drm_dev); 159 160 return nouveau_platform_power_down(gpu); 161 } 162 163 #if IS_ENABLED(CONFIG_OF) 164 static const struct of_device_id nouveau_platform_match[] = { 165 { .compatible = "nvidia,gk20a" }, 166 { } 167 }; 168 169 MODULE_DEVICE_TABLE(of, nouveau_platform_match); 170 #endif 171 172 struct platform_driver nouveau_platform_driver = { 173 .driver = { 174 .name = "nouveau", 175 .of_match_table = of_match_ptr(nouveau_platform_match), 176 }, 177 .probe = nouveau_platform_probe, 178 .remove = nouveau_platform_remove, 179 }; 180