1 /* $NetBSD: tegra_drm.c,v 1.6 2016/01/30 00:00:56 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2015 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: tegra_drm.c,v 1.6 2016/01/30 00:00:56 riastradh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/device.h> 35 #include <sys/intr.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/conf.h> 39 40 #include <uvm/uvm_extern.h> 41 #include <uvm/uvm_device.h> 42 43 #include <drm/drmP.h> 44 45 #include <arm/nvidia/tegra_reg.h> 46 #include <arm/nvidia/tegra_var.h> 47 #include <arm/nvidia/tegra_drm.h> 48 49 #include <dev/fdt/fdtvar.h> 50 51 static int tegra_drm_match(device_t, cfdata_t, void *); 52 static void tegra_drm_attach(device_t, device_t, void *); 53 54 static const char *tegra_drm_get_name(struct drm_device *); 55 static int tegra_drm_set_busid(struct drm_device *, struct drm_master *); 56 57 static int tegra_drm_load(struct drm_device *, unsigned long); 58 static int tegra_drm_unload(struct drm_device *); 59 60 static int tegra_drm_dumb_create(struct drm_file *, struct drm_device *, 61 struct drm_mode_create_dumb *); 62 static int tegra_drm_dumb_map_offset(struct drm_file *, 63 struct drm_device *, uint32_t, uint64_t *); 64 65 static const struct uvm_pagerops tegra_drm_gem_uvm_ops = { 66 .pgo_reference = drm_gem_pager_reference, 67 .pgo_detach = drm_gem_pager_detach, 68 .pgo_fault = tegra_drm_gem_fault, 69 }; 70 71 static struct drm_driver tegra_drm_driver = { 72 .driver_features = DRIVER_MODESET | DRIVER_GEM, 73 .dev_priv_size = 0, 74 .load = tegra_drm_load, 75 .unload = tegra_drm_unload, 76 77 .gem_free_object = tegra_drm_gem_free_object, 78 .mmap_object = drm_gem_or_legacy_mmap_object, 79 .gem_uvm_ops = &tegra_drm_gem_uvm_ops, 80 81 .dumb_create = tegra_drm_dumb_create, 82 .dumb_map_offset = tegra_drm_dumb_map_offset, 83 .dumb_destroy = drm_gem_dumb_destroy, 84 85 .get_vblank_counter = tegra_drm_get_vblank_counter, 86 .enable_vblank = tegra_drm_enable_vblank, 87 .disable_vblank = tegra_drm_disable_vblank, 88 89 .name = DRIVER_NAME, 90 .desc = DRIVER_DESC, 91 .date = DRIVER_DATE, 92 .major = DRIVER_MAJOR, 93 .minor = DRIVER_MINOR, 94 .patchlevel = DRIVER_PATCHLEVEL 95 }; 96 97 static const struct drm_bus tegra_drm_bus = { 98 .bus_type = DRIVER_BUS_PLATFORM, 99 .get_name = tegra_drm_get_name, 100 .set_busid = tegra_drm_set_busid 101 }; 102 103 CFATTACH_DECL_NEW(tegra_drm, sizeof(struct tegra_drm_softc), 104 tegra_drm_match, tegra_drm_attach, NULL, NULL); 105 106 static int 107 tegra_drm_match(device_t parent, cfdata_t cf, void *aux) 108 { 109 const char * compatible[] = { "nvidia,tegra124-host1x", NULL }; 110 struct fdt_attach_args * const faa = aux; 111 112 return of_match_compatible(faa->faa_phandle, compatible); 113 } 114 115 static void 116 tegra_drm_attach(device_t parent, device_t self, void *aux) 117 { 118 struct tegra_drm_softc * const sc = device_private(self); 119 struct fdt_attach_args * const faa = aux; 120 struct drm_driver * const driver = &tegra_drm_driver; 121 prop_dictionary_t prop = device_properties(self); 122 int error, node, hdmi_phandle, ddc_phandle; 123 const char * const hdmi_compat[] = { "nvidia,tegra124-hdmi", NULL }; 124 const char * const dc_compat[] = { "nvidia,tegra124-dc", NULL }; 125 const char * const hdmi_supplies[] = { 126 "hdmi-supply", "pll-supply", "vdd-supply" 127 }; 128 struct fdtbus_regulator *reg; 129 struct clk *pll_p_out0; 130 u_int n, ndc; 131 132 sc->sc_dev = self; 133 sc->sc_dmat = faa->faa_dmat; 134 sc->sc_bst = faa->faa_bst; 135 sc->sc_phandle = faa->faa_phandle; 136 137 aprint_naive("\n"); 138 aprint_normal("\n"); 139 140 sc->sc_clk_host1x = fdtbus_clock_get_index(faa->faa_phandle, 0); 141 if (sc->sc_clk_host1x == NULL) { 142 aprint_error_dev(self, "couldn't get clock host1x\n"); 143 return; 144 } 145 sc->sc_rst_host1x = fdtbus_reset_get(faa->faa_phandle, "host1x"); 146 if (sc->sc_clk_host1x == NULL || sc->sc_rst_host1x == NULL) { 147 aprint_error_dev(self, "couldn't get reset host1x\n"); 148 return; 149 } 150 151 ndc = 0; 152 hdmi_phandle = -1; 153 for (node = OF_child(faa->faa_phandle); node; node = OF_peer(node)) { 154 if (of_match_compatible(node, hdmi_compat)) { 155 sc->sc_clk_hdmi = fdtbus_clock_get(node, "hdmi"); 156 sc->sc_clk_hdmi_parent = fdtbus_clock_get(node, 157 "parent"); 158 sc->sc_rst_hdmi = fdtbus_reset_get(node, "hdmi"); 159 hdmi_phandle = node; 160 } else if (of_match_compatible(node, dc_compat) && 161 ndc < __arraycount(sc->sc_clk_dc)) { 162 sc->sc_clk_dc[ndc] = fdtbus_clock_get(node, "dc"); 163 sc->sc_clk_dc_parent[ndc] = fdtbus_clock_get(node, 164 "parent"); 165 sc->sc_rst_dc[ndc] = fdtbus_reset_get(node, "dc"); 166 ++ndc; 167 } 168 } 169 if (hdmi_phandle >= 0) { 170 ddc_phandle = fdtbus_get_phandle(hdmi_phandle, 171 "nvidia,ddc-i2c-bus"); 172 if (ddc_phandle >= 0) { 173 sc->sc_ddc = fdtbus_get_i2c_tag(ddc_phandle); 174 } 175 176 sc->sc_pin_hpd = fdtbus_gpio_acquire(hdmi_phandle, 177 "nvidia,hpd-gpio", GPIO_PIN_INPUT); 178 179 for (n = 0; n < __arraycount(hdmi_supplies); n++) { 180 const char *supply = hdmi_supplies[n]; 181 reg = fdtbus_regulator_acquire(hdmi_phandle, supply); 182 if (reg == NULL) { 183 aprint_error_dev(self, "couldn't acquire %s\n", 184 supply); 185 continue; 186 } 187 if (fdtbus_regulator_enable(reg) != 0) { 188 aprint_error_dev(self, "couldn't enable %s\n", 189 supply); 190 } 191 fdtbus_regulator_release(reg); 192 } 193 } 194 195 pll_p_out0 = clk_get("pll_p_out0"); 196 if (pll_p_out0 == NULL) { 197 aprint_error_dev(self, "couldn't get clock pll_p_out0\n"); 198 return; 199 } 200 fdtbus_reset_assert(sc->sc_rst_host1x); 201 error = clk_set_parent(sc->sc_clk_host1x, pll_p_out0); 202 if (error) { 203 aprint_error_dev(self, "couldn't set host1x clock parent: %d\n", 204 error); 205 return; 206 } 207 error = clk_set_rate(sc->sc_clk_host1x, 408000000); 208 if (error) { 209 aprint_error_dev(self, "couldn't set host1x frequency: %d\n", 210 error); 211 return; 212 } 213 error = clk_enable(sc->sc_clk_host1x); 214 if (error) { 215 aprint_error_dev(self, "couldn't enable clock host1x: %d\n", 216 error); 217 return; 218 } 219 fdtbus_reset_deassert(sc->sc_rst_host1x); 220 clk_put(pll_p_out0); 221 222 prop_dictionary_get_bool(prop, "force-dvi", &sc->sc_force_dvi); 223 224 driver->bus = &tegra_drm_bus; 225 226 sc->sc_ddev = drm_dev_alloc(driver, sc->sc_dev); 227 if (sc->sc_ddev == NULL) { 228 aprint_error_dev(self, "couldn't allocate DRM device\n"); 229 return; 230 } 231 sc->sc_ddev->dev_private = sc; 232 233 error = -drm_dev_register(sc->sc_ddev, 0); 234 if (error) { 235 drm_dev_unref(sc->sc_ddev); 236 aprint_error_dev(self, "couldn't register DRM device: %d\n", 237 error); 238 return; 239 } 240 241 aprint_normal_dev(self, "initialized %s %d.%d.%d %s on minor %d\n", 242 driver->name, driver->major, driver->minor, driver->patchlevel, 243 driver->date, sc->sc_ddev->primary->index); 244 245 return; 246 } 247 248 static const char * 249 tegra_drm_get_name(struct drm_device *ddev) 250 { 251 return DRIVER_NAME; 252 } 253 254 static int 255 tegra_drm_set_busid(struct drm_device *ddev, struct drm_master *master) 256 { 257 const char *id = "platform:tegra:0"; 258 259 master->unique = kzalloc(strlen(id) + 1, GFP_KERNEL); 260 if (master->unique == NULL) 261 return -ENOMEM; 262 strcpy(master->unique, id); 263 master->unique_len = strlen(master->unique); 264 265 return 0; 266 } 267 268 269 static int 270 tegra_drm_load(struct drm_device *ddev, unsigned long flags) 271 { 272 char *devname; 273 int error; 274 275 devname = kzalloc(strlen(DRIVER_NAME) + 1, GFP_KERNEL); 276 if (devname == NULL) { 277 return -ENOMEM; 278 } 279 strcpy(devname, DRIVER_NAME); 280 ddev->devname = devname; 281 282 error = tegra_drm_mode_init(ddev); 283 if (error) 284 goto drmerr; 285 286 error = tegra_drm_fb_init(ddev); 287 if (error) 288 goto drmerr; 289 290 return 0; 291 292 drmerr: 293 drm_mode_config_cleanup(ddev); 294 295 return error; 296 } 297 298 static int 299 tegra_drm_unload(struct drm_device *ddev) 300 { 301 drm_mode_config_cleanup(ddev); 302 303 return 0; 304 } 305 306 static int 307 tegra_drm_dumb_create(struct drm_file *file_priv, struct drm_device *ddev, 308 struct drm_mode_create_dumb *args) 309 { 310 struct tegra_gem_object *obj; 311 uint32_t handle; 312 int error; 313 314 args->pitch = args->width * ((args->bpp + 7) / 8); 315 args->size = args->pitch * args->height; 316 args->size = roundup(args->size, PAGE_SIZE); 317 args->handle = 0; 318 319 obj = tegra_drm_obj_alloc(ddev, args->size); 320 if (obj == NULL) 321 return -ENOMEM; 322 323 error = drm_gem_handle_create(file_priv, &obj->base, &handle); 324 drm_gem_object_unreference_unlocked(&obj->base); 325 if (error) { 326 tegra_drm_obj_free(obj); 327 return error; 328 } 329 330 args->handle = handle; 331 332 return 0; 333 } 334 335 static int 336 tegra_drm_dumb_map_offset(struct drm_file *file_priv, 337 struct drm_device *ddev, uint32_t handle, uint64_t *offset) 338 { 339 struct drm_gem_object *gem_obj; 340 struct tegra_gem_object *obj; 341 int error; 342 343 gem_obj = drm_gem_object_lookup(ddev, file_priv, handle); 344 if (gem_obj == NULL) 345 return -ENOENT; 346 347 obj = to_tegra_gem_obj(gem_obj); 348 349 if (drm_vma_node_has_offset(&obj->base.vma_node) == 0) { 350 error = drm_gem_create_mmap_offset(&obj->base); 351 if (error) 352 goto done; 353 } else { 354 error = 0; 355 } 356 357 *offset = drm_vma_node_offset_addr(&obj->base.vma_node); 358 359 done: 360 drm_gem_object_unreference_unlocked(&obj->base); 361 362 return error; 363 } 364