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/pmc.h> 31 32 #include "nouveau_drm.h" 33 #include "nouveau_platform.h" 34 35 static int nouveau_platform_power_up(struct nouveau_platform_gpu *gpu) 36 { 37 int err; 38 39 err = regulator_enable(gpu->vdd); 40 if (err) 41 goto err_power; 42 43 err = clk_prepare_enable(gpu->clk); 44 if (err) 45 goto err_clk; 46 err = clk_prepare_enable(gpu->clk_pwr); 47 if (err) 48 goto err_clk_pwr; 49 clk_set_rate(gpu->clk_pwr, 204000000); 50 udelay(10); 51 52 reset_control_assert(gpu->rst); 53 udelay(10); 54 55 err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); 56 if (err) 57 goto err_clamp; 58 udelay(10); 59 60 reset_control_deassert(gpu->rst); 61 udelay(10); 62 63 return 0; 64 65 err_clamp: 66 clk_disable_unprepare(gpu->clk_pwr); 67 err_clk_pwr: 68 clk_disable_unprepare(gpu->clk); 69 err_clk: 70 regulator_disable(gpu->vdd); 71 err_power: 72 return err; 73 } 74 75 static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu) 76 { 77 int err; 78 79 reset_control_assert(gpu->rst); 80 udelay(10); 81 82 clk_disable_unprepare(gpu->clk_pwr); 83 clk_disable_unprepare(gpu->clk); 84 udelay(10); 85 86 err = regulator_disable(gpu->vdd); 87 if (err) 88 return err; 89 90 return 0; 91 } 92 93 static int nouveau_platform_probe(struct platform_device *pdev) 94 { 95 struct nouveau_platform_gpu *gpu; 96 struct nouveau_platform_device *device; 97 struct drm_device *drm; 98 int err; 99 100 gpu = devm_kzalloc(&pdev->dev, sizeof(*gpu), GFP_KERNEL); 101 if (!gpu) 102 return -ENOMEM; 103 104 gpu->vdd = devm_regulator_get(&pdev->dev, "vdd"); 105 if (IS_ERR(gpu->vdd)) 106 return PTR_ERR(gpu->vdd); 107 108 gpu->rst = devm_reset_control_get(&pdev->dev, "gpu"); 109 if (IS_ERR(gpu->rst)) 110 return PTR_ERR(gpu->rst); 111 112 gpu->clk = devm_clk_get(&pdev->dev, "gpu"); 113 if (IS_ERR(gpu->clk)) 114 return PTR_ERR(gpu->clk); 115 116 gpu->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); 117 if (IS_ERR(gpu->clk_pwr)) 118 return PTR_ERR(gpu->clk_pwr); 119 120 err = nouveau_platform_power_up(gpu); 121 if (err) 122 return err; 123 124 drm = nouveau_platform_device_create(pdev, &device); 125 if (IS_ERR(drm)) { 126 err = PTR_ERR(drm); 127 goto power_down; 128 } 129 130 device->gpu = gpu; 131 132 err = drm_dev_register(drm, 0); 133 if (err < 0) 134 goto err_unref; 135 136 return 0; 137 138 err_unref: 139 drm_dev_unref(drm); 140 141 return 0; 142 143 power_down: 144 nouveau_platform_power_down(gpu); 145 146 return err; 147 } 148 149 static int nouveau_platform_remove(struct platform_device *pdev) 150 { 151 struct drm_device *drm_dev = platform_get_drvdata(pdev); 152 struct nouveau_drm *drm = nouveau_drm(drm_dev); 153 struct nouveau_device *device = nvkm_device(&drm->device); 154 struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu; 155 156 nouveau_drm_device_remove(drm_dev); 157 158 return nouveau_platform_power_down(gpu); 159 } 160 161 #if IS_ENABLED(CONFIG_OF) 162 static const struct of_device_id nouveau_platform_match[] = { 163 { .compatible = "nvidia,gk20a" }, 164 { } 165 }; 166 167 MODULE_DEVICE_TABLE(of, nouveau_platform_match); 168 #endif 169 170 struct platform_driver nouveau_platform_driver = { 171 .driver = { 172 .name = "nouveau", 173 .of_match_table = of_match_ptr(nouveau_platform_match), 174 }, 175 .probe = nouveau_platform_probe, 176 .remove = nouveau_platform_remove, 177 }; 178 179 module_platform_driver(nouveau_platform_driver); 180 181 MODULE_AUTHOR(DRIVER_AUTHOR); 182 MODULE_DESCRIPTION(DRIVER_DESC); 183 MODULE_LICENSE("GPL and additional rights"); 184