diff options
| author | Thierry Reding <treding@nvidia.com> | 2013-10-09 04:32:49 -0400 |
|---|---|---|
| committer | Thierry Reding <treding@nvidia.com> | 2013-10-31 04:55:40 -0400 |
| commit | dee8268f8fb218c9e9b604a40f7dbdd395e910f9 (patch) | |
| tree | b28f659398ca70881bccde1cef8c34357faf6964 /drivers/gpu/host1x | |
| parent | fc3be3e8fc8b3b6e800d6dc8ffb794e9d27ba5d2 (diff) | |
drm/tegra: Move driver to DRM tree
In order to make subsystem-wide changes easier, move the Tegra DRM
driver back into the DRM tree.
Signed-off-by: Thierry Reding <treding@nvidia.com>
Diffstat (limited to 'drivers/gpu/host1x')
| -rw-r--r-- | drivers/gpu/host1x/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/gpu/host1x/Makefile | 8 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/Kconfig | 29 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/bus.c | 76 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/dc.c | 1194 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/dc.h | 400 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/drm.c | 545 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/drm.h | 258 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/fb.c | 372 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/gem.c | 248 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/gem.h | 56 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/gr2d.c | 343 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/hdmi.c | 1295 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/hdmi.h | 386 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/output.c | 270 | ||||
| -rw-r--r-- | drivers/gpu/host1x/drm/rgb.c | 225 |
16 files changed, 0 insertions, 5707 deletions
diff --git a/drivers/gpu/host1x/Kconfig b/drivers/gpu/host1x/Kconfig index ccfd42b23606..7d6bed222542 100644 --- a/drivers/gpu/host1x/Kconfig +++ b/drivers/gpu/host1x/Kconfig | |||
| @@ -19,6 +19,4 @@ config TEGRA_HOST1X_FIREWALL | |||
| 19 | 19 | ||
| 20 | If unsure, choose Y. | 20 | If unsure, choose Y. |
| 21 | 21 | ||
| 22 | source "drivers/gpu/host1x/drm/Kconfig" | ||
| 23 | |||
| 24 | endif | 22 | endif |
diff --git a/drivers/gpu/host1x/Makefile b/drivers/gpu/host1x/Makefile index 616fe82ce715..889217cfb79d 100644 --- a/drivers/gpu/host1x/Makefile +++ b/drivers/gpu/host1x/Makefile | |||
| @@ -9,12 +9,4 @@ host1x-y = \ | |||
| 9 | debug.o \ | 9 | debug.o \ |
| 10 | hw/host1x01.o | 10 | hw/host1x01.o |
| 11 | 11 | ||
| 12 | ccflags-y += -Iinclude/drm | ||
| 13 | ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG | ||
| 14 | |||
| 15 | host1x-$(CONFIG_DRM_TEGRA) += drm/drm.o drm/fb.o drm/dc.o | ||
| 16 | host1x-$(CONFIG_DRM_TEGRA) += drm/output.o drm/rgb.o drm/hdmi.o | ||
| 17 | host1x-$(CONFIG_DRM_TEGRA) += drm/gem.o | ||
| 18 | host1x-$(CONFIG_DRM_TEGRA) += drm/gr2d.o | ||
| 19 | host1x-$(CONFIG_DRM_TEGRA) += drm/bus.o | ||
| 20 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o | 12 | obj-$(CONFIG_TEGRA_HOST1X) += host1x.o |
diff --git a/drivers/gpu/host1x/drm/Kconfig b/drivers/gpu/host1x/drm/Kconfig deleted file mode 100644 index 69853a4de40a..000000000000 --- a/drivers/gpu/host1x/drm/Kconfig +++ /dev/null | |||
| @@ -1,29 +0,0 @@ | |||
| 1 | config DRM_TEGRA | ||
| 2 | bool "NVIDIA Tegra DRM" | ||
| 3 | depends on DRM | ||
| 4 | select DRM_KMS_HELPER | ||
| 5 | select FB_SYS_FILLRECT | ||
| 6 | select FB_SYS_COPYAREA | ||
| 7 | select FB_SYS_IMAGEBLIT | ||
| 8 | help | ||
| 9 | Choose this option if you have an NVIDIA Tegra SoC. | ||
| 10 | |||
| 11 | To compile this driver as a module, choose M here: the module | ||
| 12 | will be called tegra-drm. | ||
| 13 | |||
| 14 | if DRM_TEGRA | ||
| 15 | |||
| 16 | config DRM_TEGRA_STAGING | ||
| 17 | bool "Enable HOST1X interface" | ||
| 18 | depends on STAGING | ||
| 19 | help | ||
| 20 | Say yes if HOST1X should be available for userspace DRM users. | ||
| 21 | |||
| 22 | If unsure, choose N. | ||
| 23 | |||
| 24 | config DRM_TEGRA_DEBUG | ||
| 25 | bool "NVIDIA Tegra DRM debug support" | ||
| 26 | help | ||
| 27 | Say yes here to enable debugging support. | ||
| 28 | |||
| 29 | endif | ||
diff --git a/drivers/gpu/host1x/drm/bus.c b/drivers/gpu/host1x/drm/bus.c deleted file mode 100644 index 565f8f7b9a47..000000000000 --- a/drivers/gpu/host1x/drm/bus.c +++ /dev/null | |||
| @@ -1,76 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2013 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 "drm.h" | ||
| 10 | |||
| 11 | static int drm_host1x_set_busid(struct drm_device *dev, | ||
| 12 | struct drm_master *master) | ||
| 13 | { | ||
| 14 | const char *device = dev_name(dev->dev); | ||
| 15 | const char *driver = dev->driver->name; | ||
| 16 | const char *bus = dev->dev->bus->name; | ||
| 17 | int length; | ||
| 18 | |||
| 19 | master->unique_len = strlen(bus) + 1 + strlen(device); | ||
| 20 | master->unique_size = master->unique_len; | ||
| 21 | |||
| 22 | master->unique = kmalloc(master->unique_len + 1, GFP_KERNEL); | ||
| 23 | if (!master->unique) | ||
| 24 | return -ENOMEM; | ||
| 25 | |||
| 26 | snprintf(master->unique, master->unique_len + 1, "%s:%s", bus, device); | ||
| 27 | |||
| 28 | length = strlen(driver) + 1 + master->unique_len; | ||
| 29 | |||
| 30 | dev->devname = kmalloc(length + 1, GFP_KERNEL); | ||
| 31 | if (!dev->devname) | ||
| 32 | return -ENOMEM; | ||
| 33 | |||
| 34 | snprintf(dev->devname, length + 1, "%s@%s", driver, master->unique); | ||
| 35 | |||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static struct drm_bus drm_host1x_bus = { | ||
| 40 | .bus_type = DRIVER_BUS_HOST1X, | ||
| 41 | .set_busid = drm_host1x_set_busid, | ||
| 42 | }; | ||
| 43 | |||
| 44 | int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device) | ||
| 45 | { | ||
| 46 | struct drm_device *drm; | ||
| 47 | int ret; | ||
| 48 | |||
| 49 | INIT_LIST_HEAD(&driver->device_list); | ||
| 50 | driver->bus = &drm_host1x_bus; | ||
| 51 | |||
| 52 | drm = drm_dev_alloc(driver, &device->dev); | ||
| 53 | if (!drm) | ||
| 54 | return -ENOMEM; | ||
| 55 | |||
| 56 | ret = drm_dev_register(drm, 0); | ||
| 57 | if (ret) | ||
| 58 | goto err_free; | ||
| 59 | |||
| 60 | DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, | ||
| 61 | driver->major, driver->minor, driver->patchlevel, | ||
| 62 | driver->date, drm->primary->index); | ||
| 63 | |||
| 64 | return 0; | ||
| 65 | |||
| 66 | err_free: | ||
| 67 | drm_dev_free(drm); | ||
| 68 | return ret; | ||
| 69 | } | ||
| 70 | |||
| 71 | void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device) | ||
| 72 | { | ||
| 73 | struct tegra_drm *tegra = dev_get_drvdata(&device->dev); | ||
| 74 | |||
| 75 | drm_put_dev(tegra->drm); | ||
| 76 | } | ||
diff --git a/drivers/gpu/host1x/drm/dc.c b/drivers/gpu/host1x/drm/dc.c deleted file mode 100644 index 588d4ba0d8cf..000000000000 --- a/drivers/gpu/host1x/drm/dc.c +++ /dev/null | |||
| @@ -1,1194 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/clk.h> | ||
| 11 | #include <linux/clk/tegra.h> | ||
| 12 | #include <linux/debugfs.h> | ||
| 13 | |||
| 14 | #include "dc.h" | ||
| 15 | #include "drm.h" | ||
| 16 | #include "gem.h" | ||
| 17 | |||
| 18 | struct tegra_plane { | ||
| 19 | struct drm_plane base; | ||
| 20 | unsigned int index; | ||
| 21 | }; | ||
| 22 | |||
| 23 | static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane) | ||
| 24 | { | ||
| 25 | return container_of(plane, struct tegra_plane, base); | ||
| 26 | } | ||
| 27 | |||
| 28 | static int tegra_plane_update(struct drm_plane *plane, struct drm_crtc *crtc, | ||
| 29 | struct drm_framebuffer *fb, int crtc_x, | ||
| 30 | int crtc_y, unsigned int crtc_w, | ||
| 31 | unsigned int crtc_h, uint32_t src_x, | ||
| 32 | uint32_t src_y, uint32_t src_w, uint32_t src_h) | ||
| 33 | { | ||
| 34 | struct tegra_plane *p = to_tegra_plane(plane); | ||
| 35 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 36 | struct tegra_dc_window window; | ||
| 37 | unsigned int i; | ||
| 38 | |||
| 39 | memset(&window, 0, sizeof(window)); | ||
| 40 | window.src.x = src_x >> 16; | ||
| 41 | window.src.y = src_y >> 16; | ||
| 42 | window.src.w = src_w >> 16; | ||
| 43 | window.src.h = src_h >> 16; | ||
| 44 | window.dst.x = crtc_x; | ||
| 45 | window.dst.y = crtc_y; | ||
| 46 | window.dst.w = crtc_w; | ||
| 47 | window.dst.h = crtc_h; | ||
| 48 | window.format = tegra_dc_format(fb->pixel_format); | ||
| 49 | window.bits_per_pixel = fb->bits_per_pixel; | ||
| 50 | |||
| 51 | for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) { | ||
| 52 | struct tegra_bo *bo = tegra_fb_get_plane(fb, i); | ||
| 53 | |||
| 54 | window.base[i] = bo->paddr + fb->offsets[i]; | ||
| 55 | |||
| 56 | /* | ||
| 57 | * Tegra doesn't support different strides for U and V planes | ||
| 58 | * so we display a warning if the user tries to display a | ||
| 59 | * framebuffer with such a configuration. | ||
| 60 | */ | ||
| 61 | if (i >= 2) { | ||
| 62 | if (fb->pitches[i] != window.stride[1]) | ||
| 63 | DRM_ERROR("unsupported UV-plane configuration\n"); | ||
| 64 | } else { | ||
| 65 | window.stride[i] = fb->pitches[i]; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | return tegra_dc_setup_window(dc, p->index, &window); | ||
| 70 | } | ||
| 71 | |||
| 72 | static int tegra_plane_disable(struct drm_plane *plane) | ||
| 73 | { | ||
| 74 | struct tegra_dc *dc = to_tegra_dc(plane->crtc); | ||
| 75 | struct tegra_plane *p = to_tegra_plane(plane); | ||
| 76 | unsigned long value; | ||
| 77 | |||
| 78 | if (!plane->crtc) | ||
| 79 | return 0; | ||
| 80 | |||
| 81 | value = WINDOW_A_SELECT << p->index; | ||
| 82 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 83 | |||
| 84 | value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS); | ||
| 85 | value &= ~WIN_ENABLE; | ||
| 86 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
| 87 | |||
| 88 | tegra_dc_writel(dc, WIN_A_UPDATE << p->index, DC_CMD_STATE_CONTROL); | ||
| 89 | tegra_dc_writel(dc, WIN_A_ACT_REQ << p->index, DC_CMD_STATE_CONTROL); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static void tegra_plane_destroy(struct drm_plane *plane) | ||
| 95 | { | ||
| 96 | tegra_plane_disable(plane); | ||
| 97 | drm_plane_cleanup(plane); | ||
| 98 | } | ||
| 99 | |||
| 100 | static const struct drm_plane_funcs tegra_plane_funcs = { | ||
| 101 | .update_plane = tegra_plane_update, | ||
| 102 | .disable_plane = tegra_plane_disable, | ||
| 103 | .destroy = tegra_plane_destroy, | ||
| 104 | }; | ||
| 105 | |||
| 106 | static const uint32_t plane_formats[] = { | ||
| 107 | DRM_FORMAT_XBGR8888, | ||
| 108 | DRM_FORMAT_XRGB8888, | ||
| 109 | DRM_FORMAT_RGB565, | ||
| 110 | DRM_FORMAT_UYVY, | ||
| 111 | DRM_FORMAT_YUV420, | ||
| 112 | DRM_FORMAT_YUV422, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) | ||
| 116 | { | ||
| 117 | unsigned int i; | ||
| 118 | int err = 0; | ||
| 119 | |||
| 120 | for (i = 0; i < 2; i++) { | ||
| 121 | struct tegra_plane *plane; | ||
| 122 | |||
| 123 | plane = devm_kzalloc(drm->dev, sizeof(*plane), GFP_KERNEL); | ||
| 124 | if (!plane) | ||
| 125 | return -ENOMEM; | ||
| 126 | |||
| 127 | plane->index = 1 + i; | ||
| 128 | |||
| 129 | err = drm_plane_init(drm, &plane->base, 1 << dc->pipe, | ||
| 130 | &tegra_plane_funcs, plane_formats, | ||
| 131 | ARRAY_SIZE(plane_formats), false); | ||
| 132 | if (err < 0) | ||
| 133 | return err; | ||
| 134 | } | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y, | ||
| 140 | struct drm_framebuffer *fb) | ||
| 141 | { | ||
| 142 | unsigned int format = tegra_dc_format(fb->pixel_format); | ||
| 143 | struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); | ||
| 144 | unsigned long value; | ||
| 145 | |||
| 146 | tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 147 | |||
| 148 | value = fb->offsets[0] + y * fb->pitches[0] + | ||
| 149 | x * fb->bits_per_pixel / 8; | ||
| 150 | |||
| 151 | tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR); | ||
| 152 | tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE); | ||
| 153 | tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH); | ||
| 154 | |||
| 155 | value = GENERAL_UPDATE | WIN_A_UPDATE; | ||
| 156 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
| 157 | |||
| 158 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | ||
| 159 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | void tegra_dc_enable_vblank(struct tegra_dc *dc) | ||
| 165 | { | ||
| 166 | unsigned long value, flags; | ||
| 167 | |||
| 168 | spin_lock_irqsave(&dc->lock, flags); | ||
| 169 | |||
| 170 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
| 171 | value |= VBLANK_INT; | ||
| 172 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 173 | |||
| 174 | spin_unlock_irqrestore(&dc->lock, flags); | ||
| 175 | } | ||
| 176 | |||
| 177 | void tegra_dc_disable_vblank(struct tegra_dc *dc) | ||
| 178 | { | ||
| 179 | unsigned long value, flags; | ||
| 180 | |||
| 181 | spin_lock_irqsave(&dc->lock, flags); | ||
| 182 | |||
| 183 | value = tegra_dc_readl(dc, DC_CMD_INT_MASK); | ||
| 184 | value &= ~VBLANK_INT; | ||
| 185 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 186 | |||
| 187 | spin_unlock_irqrestore(&dc->lock, flags); | ||
| 188 | } | ||
| 189 | |||
| 190 | static void tegra_dc_finish_page_flip(struct tegra_dc *dc) | ||
| 191 | { | ||
| 192 | struct drm_device *drm = dc->base.dev; | ||
| 193 | struct drm_crtc *crtc = &dc->base; | ||
| 194 | unsigned long flags, base; | ||
| 195 | struct tegra_bo *bo; | ||
| 196 | |||
| 197 | if (!dc->event) | ||
| 198 | return; | ||
| 199 | |||
| 200 | bo = tegra_fb_get_plane(crtc->fb, 0); | ||
| 201 | |||
| 202 | /* check if new start address has been latched */ | ||
| 203 | tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); | ||
| 204 | base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); | ||
| 205 | tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); | ||
| 206 | |||
| 207 | if (base == bo->paddr + crtc->fb->offsets[0]) { | ||
| 208 | spin_lock_irqsave(&drm->event_lock, flags); | ||
| 209 | drm_send_vblank_event(drm, dc->pipe, dc->event); | ||
| 210 | drm_vblank_put(drm, dc->pipe); | ||
| 211 | dc->event = NULL; | ||
| 212 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file) | ||
| 217 | { | ||
| 218 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 219 | struct drm_device *drm = crtc->dev; | ||
| 220 | unsigned long flags; | ||
| 221 | |||
| 222 | spin_lock_irqsave(&drm->event_lock, flags); | ||
| 223 | |||
| 224 | if (dc->event && dc->event->base.file_priv == file) { | ||
| 225 | dc->event->base.destroy(&dc->event->base); | ||
| 226 | drm_vblank_put(drm, dc->pipe); | ||
| 227 | dc->event = NULL; | ||
| 228 | } | ||
| 229 | |||
| 230 | spin_unlock_irqrestore(&drm->event_lock, flags); | ||
| 231 | } | ||
| 232 | |||
| 233 | static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, | ||
| 234 | struct drm_pending_vblank_event *event, uint32_t page_flip_flags) | ||
| 235 | { | ||
| 236 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 237 | struct drm_device *drm = crtc->dev; | ||
| 238 | |||
| 239 | if (dc->event) | ||
| 240 | return -EBUSY; | ||
| 241 | |||
| 242 | if (event) { | ||
| 243 | event->pipe = dc->pipe; | ||
| 244 | dc->event = event; | ||
| 245 | drm_vblank_get(drm, dc->pipe); | ||
| 246 | } | ||
| 247 | |||
| 248 | tegra_dc_set_base(dc, 0, 0, fb); | ||
| 249 | crtc->fb = fb; | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | } | ||
| 253 | |||
| 254 | static const struct drm_crtc_funcs tegra_crtc_funcs = { | ||
| 255 | .page_flip = tegra_dc_page_flip, | ||
| 256 | .set_config = drm_crtc_helper_set_config, | ||
| 257 | .destroy = drm_crtc_cleanup, | ||
| 258 | }; | ||
| 259 | |||
| 260 | static void tegra_crtc_disable(struct drm_crtc *crtc) | ||
| 261 | { | ||
| 262 | struct drm_device *drm = crtc->dev; | ||
| 263 | struct drm_plane *plane; | ||
| 264 | |||
| 265 | list_for_each_entry(plane, &drm->mode_config.plane_list, head) { | ||
| 266 | if (plane->crtc == crtc) { | ||
| 267 | tegra_plane_disable(plane); | ||
| 268 | plane->crtc = NULL; | ||
| 269 | |||
| 270 | if (plane->fb) { | ||
| 271 | drm_framebuffer_unreference(plane->fb); | ||
| 272 | plane->fb = NULL; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc, | ||
| 279 | const struct drm_display_mode *mode, | ||
| 280 | struct drm_display_mode *adjusted) | ||
| 281 | { | ||
| 282 | return true; | ||
| 283 | } | ||
| 284 | |||
| 285 | static inline u32 compute_dda_inc(unsigned int in, unsigned int out, bool v, | ||
| 286 | unsigned int bpp) | ||
| 287 | { | ||
| 288 | fixed20_12 outf = dfixed_init(out); | ||
| 289 | fixed20_12 inf = dfixed_init(in); | ||
| 290 | u32 dda_inc; | ||
| 291 | int max; | ||
| 292 | |||
| 293 | if (v) | ||
| 294 | max = 15; | ||
| 295 | else { | ||
| 296 | switch (bpp) { | ||
| 297 | case 2: | ||
| 298 | max = 8; | ||
| 299 | break; | ||
| 300 | |||
| 301 | default: | ||
| 302 | WARN_ON_ONCE(1); | ||
| 303 | /* fallthrough */ | ||
| 304 | case 4: | ||
| 305 | max = 4; | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | outf.full = max_t(u32, outf.full - dfixed_const(1), dfixed_const(1)); | ||
| 311 | inf.full -= dfixed_const(1); | ||
| 312 | |||
| 313 | dda_inc = dfixed_div(inf, outf); | ||
| 314 | dda_inc = min_t(u32, dda_inc, dfixed_const(max)); | ||
| 315 | |||
| 316 | return dda_inc; | ||
| 317 | } | ||
| 318 | |||
| 319 | static inline u32 compute_initial_dda(unsigned int in) | ||
| 320 | { | ||
| 321 | fixed20_12 inf = dfixed_init(in); | ||
| 322 | return dfixed_frac(inf); | ||
| 323 | } | ||
| 324 | |||
| 325 | static int tegra_dc_set_timings(struct tegra_dc *dc, | ||
| 326 | struct drm_display_mode *mode) | ||
| 327 | { | ||
| 328 | /* TODO: For HDMI compliance, h & v ref_to_sync should be set to 1 */ | ||
| 329 | unsigned int h_ref_to_sync = 0; | ||
| 330 | unsigned int v_ref_to_sync = 0; | ||
| 331 | unsigned long value; | ||
| 332 | |||
| 333 | tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS); | ||
| 334 | |||
| 335 | value = (v_ref_to_sync << 16) | h_ref_to_sync; | ||
| 336 | tegra_dc_writel(dc, value, DC_DISP_REF_TO_SYNC); | ||
| 337 | |||
| 338 | value = ((mode->vsync_end - mode->vsync_start) << 16) | | ||
| 339 | ((mode->hsync_end - mode->hsync_start) << 0); | ||
| 340 | tegra_dc_writel(dc, value, DC_DISP_SYNC_WIDTH); | ||
| 341 | |||
| 342 | value = ((mode->vtotal - mode->vsync_end) << 16) | | ||
| 343 | ((mode->htotal - mode->hsync_end) << 0); | ||
| 344 | tegra_dc_writel(dc, value, DC_DISP_BACK_PORCH); | ||
| 345 | |||
| 346 | value = ((mode->vsync_start - mode->vdisplay) << 16) | | ||
| 347 | ((mode->hsync_start - mode->hdisplay) << 0); | ||
| 348 | tegra_dc_writel(dc, value, DC_DISP_FRONT_PORCH); | ||
| 349 | |||
| 350 | value = (mode->vdisplay << 16) | mode->hdisplay; | ||
| 351 | tegra_dc_writel(dc, value, DC_DISP_ACTIVE); | ||
| 352 | |||
| 353 | return 0; | ||
| 354 | } | ||
| 355 | |||
| 356 | static int tegra_crtc_setup_clk(struct drm_crtc *crtc, | ||
| 357 | struct drm_display_mode *mode, | ||
| 358 | unsigned long *div) | ||
| 359 | { | ||
| 360 | unsigned long pclk = mode->clock * 1000, rate; | ||
| 361 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 362 | struct tegra_output *output = NULL; | ||
| 363 | struct drm_encoder *encoder; | ||
| 364 | long err; | ||
| 365 | |||
| 366 | list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head) | ||
| 367 | if (encoder->crtc == crtc) { | ||
| 368 | output = encoder_to_output(encoder); | ||
| 369 | break; | ||
| 370 | } | ||
| 371 | |||
| 372 | if (!output) | ||
| 373 | return -ENODEV; | ||
| 374 | |||
| 375 | /* | ||
| 376 | * This assumes that the display controller will divide its parent | ||
| 377 | * clock by 2 to generate the pixel clock. | ||
| 378 | */ | ||
| 379 | err = tegra_output_setup_clock(output, dc->clk, pclk * 2); | ||
| 380 | if (err < 0) { | ||
| 381 | dev_err(dc->dev, "failed to setup clock: %ld\n", err); | ||
| 382 | return err; | ||
| 383 | } | ||
| 384 | |||
| 385 | rate = clk_get_rate(dc->clk); | ||
| 386 | *div = (rate * 2 / pclk) - 2; | ||
| 387 | |||
| 388 | DRM_DEBUG_KMS("rate: %lu, div: %lu\n", rate, *div); | ||
| 389 | |||
| 390 | return 0; | ||
| 391 | } | ||
| 392 | |||
| 393 | static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar) | ||
| 394 | { | ||
| 395 | switch (format) { | ||
| 396 | case WIN_COLOR_DEPTH_YCbCr422: | ||
| 397 | case WIN_COLOR_DEPTH_YUV422: | ||
| 398 | if (planar) | ||
| 399 | *planar = false; | ||
| 400 | |||
| 401 | return true; | ||
| 402 | |||
| 403 | case WIN_COLOR_DEPTH_YCbCr420P: | ||
| 404 | case WIN_COLOR_DEPTH_YUV420P: | ||
| 405 | case WIN_COLOR_DEPTH_YCbCr422P: | ||
| 406 | case WIN_COLOR_DEPTH_YUV422P: | ||
| 407 | case WIN_COLOR_DEPTH_YCbCr422R: | ||
| 408 | case WIN_COLOR_DEPTH_YUV422R: | ||
| 409 | case WIN_COLOR_DEPTH_YCbCr422RA: | ||
| 410 | case WIN_COLOR_DEPTH_YUV422RA: | ||
| 411 | if (planar) | ||
| 412 | *planar = true; | ||
| 413 | |||
| 414 | return true; | ||
| 415 | } | ||
| 416 | |||
| 417 | return false; | ||
| 418 | } | ||
| 419 | |||
| 420 | int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | ||
| 421 | const struct tegra_dc_window *window) | ||
| 422 | { | ||
| 423 | unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; | ||
| 424 | unsigned long value; | ||
| 425 | bool yuv, planar; | ||
| 426 | |||
| 427 | /* | ||
| 428 | * For YUV planar modes, the number of bytes per pixel takes into | ||
| 429 | * account only the luma component and therefore is 1. | ||
| 430 | */ | ||
| 431 | yuv = tegra_dc_format_is_yuv(window->format, &planar); | ||
| 432 | if (!yuv) | ||
| 433 | bpp = window->bits_per_pixel / 8; | ||
| 434 | else | ||
| 435 | bpp = planar ? 1 : 2; | ||
| 436 | |||
| 437 | value = WINDOW_A_SELECT << index; | ||
| 438 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 439 | |||
| 440 | tegra_dc_writel(dc, window->format, DC_WIN_COLOR_DEPTH); | ||
| 441 | tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP); | ||
| 442 | |||
| 443 | value = V_POSITION(window->dst.y) | H_POSITION(window->dst.x); | ||
| 444 | tegra_dc_writel(dc, value, DC_WIN_POSITION); | ||
| 445 | |||
| 446 | value = V_SIZE(window->dst.h) | H_SIZE(window->dst.w); | ||
| 447 | tegra_dc_writel(dc, value, DC_WIN_SIZE); | ||
| 448 | |||
| 449 | h_offset = window->src.x * bpp; | ||
| 450 | v_offset = window->src.y; | ||
| 451 | h_size = window->src.w * bpp; | ||
| 452 | v_size = window->src.h; | ||
| 453 | |||
| 454 | value = V_PRESCALED_SIZE(v_size) | H_PRESCALED_SIZE(h_size); | ||
| 455 | tegra_dc_writel(dc, value, DC_WIN_PRESCALED_SIZE); | ||
| 456 | |||
| 457 | /* | ||
| 458 | * For DDA computations the number of bytes per pixel for YUV planar | ||
| 459 | * modes needs to take into account all Y, U and V components. | ||
| 460 | */ | ||
| 461 | if (yuv && planar) | ||
| 462 | bpp = 2; | ||
| 463 | |||
| 464 | h_dda = compute_dda_inc(window->src.w, window->dst.w, false, bpp); | ||
| 465 | v_dda = compute_dda_inc(window->src.h, window->dst.h, true, bpp); | ||
| 466 | |||
| 467 | value = V_DDA_INC(v_dda) | H_DDA_INC(h_dda); | ||
| 468 | tegra_dc_writel(dc, value, DC_WIN_DDA_INC); | ||
| 469 | |||
| 470 | h_dda = compute_initial_dda(window->src.x); | ||
| 471 | v_dda = compute_initial_dda(window->src.y); | ||
| 472 | |||
| 473 | tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA); | ||
| 474 | tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA); | ||
| 475 | |||
| 476 | tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE); | ||
| 477 | tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE); | ||
| 478 | |||
| 479 | tegra_dc_writel(dc, window->base[0], DC_WINBUF_START_ADDR); | ||
| 480 | |||
| 481 | if (yuv && planar) { | ||
| 482 | tegra_dc_writel(dc, window->base[1], DC_WINBUF_START_ADDR_U); | ||
| 483 | tegra_dc_writel(dc, window->base[2], DC_WINBUF_START_ADDR_V); | ||
| 484 | value = window->stride[1] << 16 | window->stride[0]; | ||
| 485 | tegra_dc_writel(dc, value, DC_WIN_LINE_STRIDE); | ||
| 486 | } else { | ||
| 487 | tegra_dc_writel(dc, window->stride[0], DC_WIN_LINE_STRIDE); | ||
| 488 | } | ||
| 489 | |||
| 490 | tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET); | ||
| 491 | tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET); | ||
| 492 | |||
| 493 | value = WIN_ENABLE; | ||
| 494 | |||
| 495 | if (yuv) { | ||
| 496 | /* setup default colorspace conversion coefficients */ | ||
| 497 | tegra_dc_writel(dc, 0x00f0, DC_WIN_CSC_YOF); | ||
| 498 | tegra_dc_writel(dc, 0x012a, DC_WIN_CSC_KYRGB); | ||
| 499 | tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KUR); | ||
| 500 | tegra_dc_writel(dc, 0x0198, DC_WIN_CSC_KVR); | ||
| 501 | tegra_dc_writel(dc, 0x039b, DC_WIN_CSC_KUG); | ||
| 502 | tegra_dc_writel(dc, 0x032f, DC_WIN_CSC_KVG); | ||
| 503 | tegra_dc_writel(dc, 0x0204, DC_WIN_CSC_KUB); | ||
| 504 | tegra_dc_writel(dc, 0x0000, DC_WIN_CSC_KVB); | ||
| 505 | |||
| 506 | value |= CSC_ENABLE; | ||
| 507 | } else if (window->bits_per_pixel < 24) { | ||
| 508 | value |= COLOR_EXPAND; | ||
| 509 | } | ||
| 510 | |||
| 511 | tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS); | ||
| 512 | |||
| 513 | /* | ||
| 514 | * Disable blending and assume Window A is the bottom-most window, | ||
| 515 | * Window C is the top-most window and Window B is in the middle. | ||
| 516 | */ | ||
| 517 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_NOKEY); | ||
| 518 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_1WIN); | ||
| 519 | |||
| 520 | switch (index) { | ||
| 521 | case 0: | ||
| 522 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_X); | ||
| 523 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); | ||
| 524 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); | ||
| 525 | break; | ||
| 526 | |||
| 527 | case 1: | ||
| 528 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); | ||
| 529 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_2WIN_Y); | ||
| 530 | tegra_dc_writel(dc, 0x000000, DC_WIN_BLEND_3WIN_XY); | ||
| 531 | break; | ||
| 532 | |||
| 533 | case 2: | ||
| 534 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_X); | ||
| 535 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_2WIN_Y); | ||
| 536 | tegra_dc_writel(dc, 0xffff00, DC_WIN_BLEND_3WIN_XY); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | |||
| 540 | tegra_dc_writel(dc, WIN_A_UPDATE << index, DC_CMD_STATE_CONTROL); | ||
| 541 | tegra_dc_writel(dc, WIN_A_ACT_REQ << index, DC_CMD_STATE_CONTROL); | ||
| 542 | |||
| 543 | return 0; | ||
| 544 | } | ||
| 545 | |||
| 546 | unsigned int tegra_dc_format(uint32_t format) | ||
| 547 | { | ||
| 548 | switch (format) { | ||
| 549 | case DRM_FORMAT_XBGR8888: | ||
| 550 | return WIN_COLOR_DEPTH_R8G8B8A8; | ||
| 551 | |||
| 552 | case DRM_FORMAT_XRGB8888: | ||
| 553 | return WIN_COLOR_DEPTH_B8G8R8A8; | ||
| 554 | |||
| 555 | case DRM_FORMAT_RGB565: | ||
| 556 | return WIN_COLOR_DEPTH_B5G6R5; | ||
| 557 | |||
| 558 | case DRM_FORMAT_UYVY: | ||
| 559 | return WIN_COLOR_DEPTH_YCbCr422; | ||
| 560 | |||
| 561 | case DRM_FORMAT_YUV420: | ||
| 562 | return WIN_COLOR_DEPTH_YCbCr420P; | ||
| 563 | |||
| 564 | case DRM_FORMAT_YUV422: | ||
| 565 | return WIN_COLOR_DEPTH_YCbCr422P; | ||
| 566 | |||
| 567 | default: | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | |||
| 571 | WARN(1, "unsupported pixel format %u, using default\n", format); | ||
| 572 | return WIN_COLOR_DEPTH_B8G8R8A8; | ||
| 573 | } | ||
| 574 | |||
| 575 | static int tegra_crtc_mode_set(struct drm_crtc *crtc, | ||
| 576 | struct drm_display_mode *mode, | ||
| 577 | struct drm_display_mode *adjusted, | ||
| 578 | int x, int y, struct drm_framebuffer *old_fb) | ||
| 579 | { | ||
| 580 | struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0); | ||
| 581 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 582 | struct tegra_dc_window window; | ||
| 583 | unsigned long div, value; | ||
| 584 | int err; | ||
| 585 | |||
| 586 | drm_vblank_pre_modeset(crtc->dev, dc->pipe); | ||
| 587 | |||
| 588 | err = tegra_crtc_setup_clk(crtc, mode, &div); | ||
| 589 | if (err) { | ||
| 590 | dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err); | ||
| 591 | return err; | ||
| 592 | } | ||
| 593 | |||
| 594 | /* program display mode */ | ||
| 595 | tegra_dc_set_timings(dc, mode); | ||
| 596 | |||
| 597 | value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; | ||
| 598 | tegra_dc_writel(dc, value, DC_DISP_DATA_ENABLE_OPTIONS); | ||
| 599 | |||
| 600 | value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1)); | ||
| 601 | value &= ~LVS_OUTPUT_POLARITY_LOW; | ||
| 602 | value &= ~LHS_OUTPUT_POLARITY_LOW; | ||
| 603 | tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1)); | ||
| 604 | |||
| 605 | value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB | | ||
| 606 | DISP_ORDER_RED_BLUE; | ||
| 607 | tegra_dc_writel(dc, value, DC_DISP_DISP_INTERFACE_CONTROL); | ||
| 608 | |||
| 609 | tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS); | ||
| 610 | |||
| 611 | value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; | ||
| 612 | tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); | ||
| 613 | |||
| 614 | /* setup window parameters */ | ||
| 615 | memset(&window, 0, sizeof(window)); | ||
| 616 | window.src.x = 0; | ||
| 617 | window.src.y = 0; | ||
| 618 | window.src.w = mode->hdisplay; | ||
| 619 | window.src.h = mode->vdisplay; | ||
| 620 | window.dst.x = 0; | ||
| 621 | window.dst.y = 0; | ||
| 622 | window.dst.w = mode->hdisplay; | ||
| 623 | window.dst.h = mode->vdisplay; | ||
| 624 | window.format = tegra_dc_format(crtc->fb->pixel_format); | ||
| 625 | window.bits_per_pixel = crtc->fb->bits_per_pixel; | ||
| 626 | window.stride[0] = crtc->fb->pitches[0]; | ||
| 627 | window.base[0] = bo->paddr; | ||
| 628 | |||
| 629 | err = tegra_dc_setup_window(dc, 0, &window); | ||
| 630 | if (err < 0) | ||
| 631 | dev_err(dc->dev, "failed to enable root plane\n"); | ||
| 632 | |||
| 633 | return 0; | ||
| 634 | } | ||
| 635 | |||
| 636 | static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, | ||
| 637 | struct drm_framebuffer *old_fb) | ||
| 638 | { | ||
| 639 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 640 | |||
| 641 | return tegra_dc_set_base(dc, x, y, crtc->fb); | ||
| 642 | } | ||
| 643 | |||
| 644 | static void tegra_crtc_prepare(struct drm_crtc *crtc) | ||
| 645 | { | ||
| 646 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 647 | unsigned int syncpt; | ||
| 648 | unsigned long value; | ||
| 649 | |||
| 650 | /* hardware initialization */ | ||
| 651 | tegra_periph_reset_deassert(dc->clk); | ||
| 652 | usleep_range(10000, 20000); | ||
| 653 | |||
| 654 | if (dc->pipe) | ||
| 655 | syncpt = SYNCPT_VBLANK1; | ||
| 656 | else | ||
| 657 | syncpt = SYNCPT_VBLANK0; | ||
| 658 | |||
| 659 | /* initialize display controller */ | ||
| 660 | tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
| 661 | tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); | ||
| 662 | |||
| 663 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT; | ||
| 664 | tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); | ||
| 665 | |||
| 666 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
| 667 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
| 668 | tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); | ||
| 669 | |||
| 670 | value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
| 671 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; | ||
| 672 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); | ||
| 673 | |||
| 674 | value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND); | ||
| 675 | value |= DISP_CTRL_MODE_C_DISPLAY; | ||
| 676 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); | ||
| 677 | |||
| 678 | /* initialize timer */ | ||
| 679 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | | ||
| 680 | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); | ||
| 681 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
| 682 | |||
| 683 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | | ||
| 684 | WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); | ||
| 685 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
| 686 | |||
| 687 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | ||
| 688 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
| 689 | |||
| 690 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT; | ||
| 691 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
| 692 | } | ||
| 693 | |||
| 694 | static void tegra_crtc_commit(struct drm_crtc *crtc) | ||
| 695 | { | ||
| 696 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 697 | unsigned long value; | ||
| 698 | |||
| 699 | value = GENERAL_UPDATE | WIN_A_UPDATE; | ||
| 700 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
| 701 | |||
| 702 | value = GENERAL_ACT_REQ | WIN_A_ACT_REQ; | ||
| 703 | tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); | ||
| 704 | |||
| 705 | drm_vblank_post_modeset(crtc->dev, dc->pipe); | ||
| 706 | } | ||
| 707 | |||
| 708 | static void tegra_crtc_load_lut(struct drm_crtc *crtc) | ||
| 709 | { | ||
| 710 | } | ||
| 711 | |||
| 712 | static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { | ||
| 713 | .disable = tegra_crtc_disable, | ||
| 714 | .mode_fixup = tegra_crtc_mode_fixup, | ||
| 715 | .mode_set = tegra_crtc_mode_set, | ||
| 716 | .mode_set_base = tegra_crtc_mode_set_base, | ||
| 717 | .prepare = tegra_crtc_prepare, | ||
| 718 | .commit = tegra_crtc_commit, | ||
| 719 | .load_lut = tegra_crtc_load_lut, | ||
| 720 | }; | ||
| 721 | |||
| 722 | static irqreturn_t tegra_dc_irq(int irq, void *data) | ||
| 723 | { | ||
| 724 | struct tegra_dc *dc = data; | ||
| 725 | unsigned long status; | ||
| 726 | |||
| 727 | status = tegra_dc_readl(dc, DC_CMD_INT_STATUS); | ||
| 728 | tegra_dc_writel(dc, status, DC_CMD_INT_STATUS); | ||
| 729 | |||
| 730 | if (status & FRAME_END_INT) { | ||
| 731 | /* | ||
| 732 | dev_dbg(dc->dev, "%s(): frame end\n", __func__); | ||
| 733 | */ | ||
| 734 | } | ||
| 735 | |||
| 736 | if (status & VBLANK_INT) { | ||
| 737 | /* | ||
| 738 | dev_dbg(dc->dev, "%s(): vertical blank\n", __func__); | ||
| 739 | */ | ||
| 740 | drm_handle_vblank(dc->base.dev, dc->pipe); | ||
| 741 | tegra_dc_finish_page_flip(dc); | ||
| 742 | } | ||
| 743 | |||
| 744 | if (status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)) { | ||
| 745 | /* | ||
| 746 | dev_dbg(dc->dev, "%s(): underflow\n", __func__); | ||
| 747 | */ | ||
| 748 | } | ||
| 749 | |||
| 750 | return IRQ_HANDLED; | ||
| 751 | } | ||
| 752 | |||
| 753 | static int tegra_dc_show_regs(struct seq_file *s, void *data) | ||
| 754 | { | ||
| 755 | struct drm_info_node *node = s->private; | ||
| 756 | struct tegra_dc *dc = node->info_ent->data; | ||
| 757 | |||
| 758 | #define DUMP_REG(name) \ | ||
| 759 | seq_printf(s, "%-40s %#05x %08lx\n", #name, name, \ | ||
| 760 | tegra_dc_readl(dc, name)) | ||
| 761 | |||
| 762 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT); | ||
| 763 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
| 764 | DUMP_REG(DC_CMD_GENERAL_INCR_SYNCPT_ERROR); | ||
| 765 | DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT); | ||
| 766 | DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_CNTRL); | ||
| 767 | DUMP_REG(DC_CMD_WIN_A_INCR_SYNCPT_ERROR); | ||
| 768 | DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT); | ||
| 769 | DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_CNTRL); | ||
| 770 | DUMP_REG(DC_CMD_WIN_B_INCR_SYNCPT_ERROR); | ||
| 771 | DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT); | ||
| 772 | DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_CNTRL); | ||
| 773 | DUMP_REG(DC_CMD_WIN_C_INCR_SYNCPT_ERROR); | ||
| 774 | DUMP_REG(DC_CMD_CONT_SYNCPT_VSYNC); | ||
| 775 | DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0); | ||
| 776 | DUMP_REG(DC_CMD_DISPLAY_COMMAND); | ||
| 777 | DUMP_REG(DC_CMD_SIGNAL_RAISE); | ||
| 778 | DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL); | ||
| 779 | DUMP_REG(DC_CMD_INT_STATUS); | ||
| 780 | DUMP_REG(DC_CMD_INT_MASK); | ||
| 781 | DUMP_REG(DC_CMD_INT_ENABLE); | ||
| 782 | DUMP_REG(DC_CMD_INT_TYPE); | ||
| 783 | DUMP_REG(DC_CMD_INT_POLARITY); | ||
| 784 | DUMP_REG(DC_CMD_SIGNAL_RAISE1); | ||
| 785 | DUMP_REG(DC_CMD_SIGNAL_RAISE2); | ||
| 786 | DUMP_REG(DC_CMD_SIGNAL_RAISE3); | ||
| 787 | DUMP_REG(DC_CMD_STATE_ACCESS); | ||
| 788 | DUMP_REG(DC_CMD_STATE_CONTROL); | ||
| 789 | DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER); | ||
| 790 | DUMP_REG(DC_CMD_REG_ACT_CONTROL); | ||
| 791 | DUMP_REG(DC_COM_CRC_CONTROL); | ||
| 792 | DUMP_REG(DC_COM_CRC_CHECKSUM); | ||
| 793 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(0)); | ||
| 794 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(1)); | ||
| 795 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(2)); | ||
| 796 | DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE(3)); | ||
| 797 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(0)); | ||
| 798 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(1)); | ||
| 799 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(2)); | ||
| 800 | DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY(3)); | ||
| 801 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(0)); | ||
| 802 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(1)); | ||
| 803 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(2)); | ||
| 804 | DUMP_REG(DC_COM_PIN_OUTPUT_DATA(3)); | ||
| 805 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(0)); | ||
| 806 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(1)); | ||
| 807 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(2)); | ||
| 808 | DUMP_REG(DC_COM_PIN_INPUT_ENABLE(3)); | ||
| 809 | DUMP_REG(DC_COM_PIN_INPUT_DATA(0)); | ||
| 810 | DUMP_REG(DC_COM_PIN_INPUT_DATA(1)); | ||
| 811 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(0)); | ||
| 812 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(1)); | ||
| 813 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(2)); | ||
| 814 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(3)); | ||
| 815 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(4)); | ||
| 816 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(5)); | ||
| 817 | DUMP_REG(DC_COM_PIN_OUTPUT_SELECT(6)); | ||
| 818 | DUMP_REG(DC_COM_PIN_MISC_CONTROL); | ||
| 819 | DUMP_REG(DC_COM_PIN_PM0_CONTROL); | ||
| 820 | DUMP_REG(DC_COM_PIN_PM0_DUTY_CYCLE); | ||
| 821 | DUMP_REG(DC_COM_PIN_PM1_CONTROL); | ||
| 822 | DUMP_REG(DC_COM_PIN_PM1_DUTY_CYCLE); | ||
| 823 | DUMP_REG(DC_COM_SPI_CONTROL); | ||
| 824 | DUMP_REG(DC_COM_SPI_START_BYTE); | ||
| 825 | DUMP_REG(DC_COM_HSPI_WRITE_DATA_AB); | ||
| 826 | DUMP_REG(DC_COM_HSPI_WRITE_DATA_CD); | ||
| 827 | DUMP_REG(DC_COM_HSPI_CS_DC); | ||
| 828 | DUMP_REG(DC_COM_SCRATCH_REGISTER_A); | ||
| 829 | DUMP_REG(DC_COM_SCRATCH_REGISTER_B); | ||
| 830 | DUMP_REG(DC_COM_GPIO_CTRL); | ||
| 831 | DUMP_REG(DC_COM_GPIO_DEBOUNCE_COUNTER); | ||
| 832 | DUMP_REG(DC_COM_CRC_CHECKSUM_LATCHED); | ||
| 833 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
| 834 | DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1); | ||
| 835 | DUMP_REG(DC_DISP_DISP_WIN_OPTIONS); | ||
| 836 | DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
| 837 | DUMP_REG(DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
| 838 | DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS); | ||
| 839 | DUMP_REG(DC_DISP_REF_TO_SYNC); | ||
| 840 | DUMP_REG(DC_DISP_SYNC_WIDTH); | ||
| 841 | DUMP_REG(DC_DISP_BACK_PORCH); | ||
| 842 | DUMP_REG(DC_DISP_ACTIVE); | ||
| 843 | DUMP_REG(DC_DISP_FRONT_PORCH); | ||
| 844 | DUMP_REG(DC_DISP_H_PULSE0_CONTROL); | ||
| 845 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_A); | ||
| 846 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_B); | ||
| 847 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_C); | ||
| 848 | DUMP_REG(DC_DISP_H_PULSE0_POSITION_D); | ||
| 849 | DUMP_REG(DC_DISP_H_PULSE1_CONTROL); | ||
| 850 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_A); | ||
| 851 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_B); | ||
| 852 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_C); | ||
| 853 | DUMP_REG(DC_DISP_H_PULSE1_POSITION_D); | ||
| 854 | DUMP_REG(DC_DISP_H_PULSE2_CONTROL); | ||
| 855 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_A); | ||
| 856 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_B); | ||
| 857 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_C); | ||
| 858 | DUMP_REG(DC_DISP_H_PULSE2_POSITION_D); | ||
| 859 | DUMP_REG(DC_DISP_V_PULSE0_CONTROL); | ||
| 860 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_A); | ||
| 861 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_B); | ||
| 862 | DUMP_REG(DC_DISP_V_PULSE0_POSITION_C); | ||
| 863 | DUMP_REG(DC_DISP_V_PULSE1_CONTROL); | ||
| 864 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_A); | ||
| 865 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_B); | ||
| 866 | DUMP_REG(DC_DISP_V_PULSE1_POSITION_C); | ||
| 867 | DUMP_REG(DC_DISP_V_PULSE2_CONTROL); | ||
| 868 | DUMP_REG(DC_DISP_V_PULSE2_POSITION_A); | ||
| 869 | DUMP_REG(DC_DISP_V_PULSE3_CONTROL); | ||
| 870 | DUMP_REG(DC_DISP_V_PULSE3_POSITION_A); | ||
| 871 | DUMP_REG(DC_DISP_M0_CONTROL); | ||
| 872 | DUMP_REG(DC_DISP_M1_CONTROL); | ||
| 873 | DUMP_REG(DC_DISP_DI_CONTROL); | ||
| 874 | DUMP_REG(DC_DISP_PP_CONTROL); | ||
| 875 | DUMP_REG(DC_DISP_PP_SELECT_A); | ||
| 876 | DUMP_REG(DC_DISP_PP_SELECT_B); | ||
| 877 | DUMP_REG(DC_DISP_PP_SELECT_C); | ||
| 878 | DUMP_REG(DC_DISP_PP_SELECT_D); | ||
| 879 | DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL); | ||
| 880 | DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL); | ||
| 881 | DUMP_REG(DC_DISP_DISP_COLOR_CONTROL); | ||
| 882 | DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS); | ||
| 883 | DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS); | ||
| 884 | DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS); | ||
| 885 | DUMP_REG(DC_DISP_LCD_SPI_OPTIONS); | ||
| 886 | DUMP_REG(DC_DISP_BORDER_COLOR); | ||
| 887 | DUMP_REG(DC_DISP_COLOR_KEY0_LOWER); | ||
| 888 | DUMP_REG(DC_DISP_COLOR_KEY0_UPPER); | ||
| 889 | DUMP_REG(DC_DISP_COLOR_KEY1_LOWER); | ||
| 890 | DUMP_REG(DC_DISP_COLOR_KEY1_UPPER); | ||
| 891 | DUMP_REG(DC_DISP_CURSOR_FOREGROUND); | ||
| 892 | DUMP_REG(DC_DISP_CURSOR_BACKGROUND); | ||
| 893 | DUMP_REG(DC_DISP_CURSOR_START_ADDR); | ||
| 894 | DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS); | ||
| 895 | DUMP_REG(DC_DISP_CURSOR_POSITION); | ||
| 896 | DUMP_REG(DC_DISP_CURSOR_POSITION_NS); | ||
| 897 | DUMP_REG(DC_DISP_INIT_SEQ_CONTROL); | ||
| 898 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A); | ||
| 899 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B); | ||
| 900 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C); | ||
| 901 | DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D); | ||
| 902 | DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL); | ||
| 903 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST); | ||
| 904 | DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST); | ||
| 905 | DUMP_REG(DC_DISP_MCCIF_DISPLAY1A_HYST); | ||
| 906 | DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST); | ||
| 907 | DUMP_REG(DC_DISP_DAC_CRT_CTRL); | ||
| 908 | DUMP_REG(DC_DISP_DISP_MISC_CONTROL); | ||
| 909 | DUMP_REG(DC_DISP_SD_CONTROL); | ||
| 910 | DUMP_REG(DC_DISP_SD_CSC_COEFF); | ||
| 911 | DUMP_REG(DC_DISP_SD_LUT(0)); | ||
| 912 | DUMP_REG(DC_DISP_SD_LUT(1)); | ||
| 913 | DUMP_REG(DC_DISP_SD_LUT(2)); | ||
| 914 | DUMP_REG(DC_DISP_SD_LUT(3)); | ||
| 915 | DUMP_REG(DC_DISP_SD_LUT(4)); | ||
| 916 | DUMP_REG(DC_DISP_SD_LUT(5)); | ||
| 917 | DUMP_REG(DC_DISP_SD_LUT(6)); | ||
| 918 | DUMP_REG(DC_DISP_SD_LUT(7)); | ||
| 919 | DUMP_REG(DC_DISP_SD_LUT(8)); | ||
| 920 | DUMP_REG(DC_DISP_SD_FLICKER_CONTROL); | ||
| 921 | DUMP_REG(DC_DISP_DC_PIXEL_COUNT); | ||
| 922 | DUMP_REG(DC_DISP_SD_HISTOGRAM(0)); | ||
| 923 | DUMP_REG(DC_DISP_SD_HISTOGRAM(1)); | ||
| 924 | DUMP_REG(DC_DISP_SD_HISTOGRAM(2)); | ||
| 925 | DUMP_REG(DC_DISP_SD_HISTOGRAM(3)); | ||
| 926 | DUMP_REG(DC_DISP_SD_HISTOGRAM(4)); | ||
| 927 | DUMP_REG(DC_DISP_SD_HISTOGRAM(5)); | ||
| 928 | DUMP_REG(DC_DISP_SD_HISTOGRAM(6)); | ||
| 929 | DUMP_REG(DC_DISP_SD_HISTOGRAM(7)); | ||
| 930 | DUMP_REG(DC_DISP_SD_BL_TF(0)); | ||
| 931 | DUMP_REG(DC_DISP_SD_BL_TF(1)); | ||
| 932 | DUMP_REG(DC_DISP_SD_BL_TF(2)); | ||
| 933 | DUMP_REG(DC_DISP_SD_BL_TF(3)); | ||
| 934 | DUMP_REG(DC_DISP_SD_BL_CONTROL); | ||
| 935 | DUMP_REG(DC_DISP_SD_HW_K_VALUES); | ||
| 936 | DUMP_REG(DC_DISP_SD_MAN_K_VALUES); | ||
| 937 | DUMP_REG(DC_WIN_WIN_OPTIONS); | ||
| 938 | DUMP_REG(DC_WIN_BYTE_SWAP); | ||
| 939 | DUMP_REG(DC_WIN_BUFFER_CONTROL); | ||
| 940 | DUMP_REG(DC_WIN_COLOR_DEPTH); | ||
| 941 | DUMP_REG(DC_WIN_POSITION); | ||
| 942 | DUMP_REG(DC_WIN_SIZE); | ||
| 943 | DUMP_REG(DC_WIN_PRESCALED_SIZE); | ||
| 944 | DUMP_REG(DC_WIN_H_INITIAL_DDA); | ||
| 945 | DUMP_REG(DC_WIN_V_INITIAL_DDA); | ||
| 946 | DUMP_REG(DC_WIN_DDA_INC); | ||
| 947 | DUMP_REG(DC_WIN_LINE_STRIDE); | ||
| 948 | DUMP_REG(DC_WIN_BUF_STRIDE); | ||
| 949 | DUMP_REG(DC_WIN_UV_BUF_STRIDE); | ||
| 950 | DUMP_REG(DC_WIN_BUFFER_ADDR_MODE); | ||
| 951 | DUMP_REG(DC_WIN_DV_CONTROL); | ||
| 952 | DUMP_REG(DC_WIN_BLEND_NOKEY); | ||
| 953 | DUMP_REG(DC_WIN_BLEND_1WIN); | ||
| 954 | DUMP_REG(DC_WIN_BLEND_2WIN_X); | ||
| 955 | DUMP_REG(DC_WIN_BLEND_2WIN_Y); | ||
| 956 | DUMP_REG(DC_WIN_BLEND_3WIN_XY); | ||
| 957 | DUMP_REG(DC_WIN_HP_FETCH_CONTROL); | ||
| 958 | DUMP_REG(DC_WINBUF_START_ADDR); | ||
| 959 | DUMP_REG(DC_WINBUF_START_ADDR_NS); | ||
| 960 | DUMP_REG(DC_WINBUF_START_ADDR_U); | ||
| 961 | DUMP_REG(DC_WINBUF_START_ADDR_U_NS); | ||
| 962 | DUMP_REG(DC_WINBUF_START_ADDR_V); | ||
| 963 | DUMP_REG(DC_WINBUF_START_ADDR_V_NS); | ||
| 964 | DUMP_REG(DC_WINBUF_ADDR_H_OFFSET); | ||
| 965 | DUMP_REG(DC_WINBUF_ADDR_H_OFFSET_NS); | ||
| 966 | DUMP_REG(DC_WINBUF_ADDR_V_OFFSET); | ||
| 967 | DUMP_REG(DC_WINBUF_ADDR_V_OFFSET_NS); | ||
| 968 | DUMP_REG(DC_WINBUF_UFLOW_STATUS); | ||
| 969 | DUMP_REG(DC_WINBUF_AD_UFLOW_STATUS); | ||
| 970 | DUMP_REG(DC_WINBUF_BD_UFLOW_STATUS); | ||
| 971 | DUMP_REG(DC_WINBUF_CD_UFLOW_STATUS); | ||
| 972 | |||
| 973 | #undef DUMP_REG | ||
| 974 | |||
| 975 | return 0; | ||
| 976 | } | ||
| 977 | |||
| 978 | static struct drm_info_list debugfs_files[] = { | ||
| 979 | { "regs", tegra_dc_show_regs, 0, NULL }, | ||
| 980 | }; | ||
| 981 | |||
| 982 | static int tegra_dc_debugfs_init(struct tegra_dc *dc, struct drm_minor *minor) | ||
| 983 | { | ||
| 984 | unsigned int i; | ||
| 985 | char *name; | ||
| 986 | int err; | ||
| 987 | |||
| 988 | name = kasprintf(GFP_KERNEL, "dc.%d", dc->pipe); | ||
| 989 | dc->debugfs = debugfs_create_dir(name, minor->debugfs_root); | ||
| 990 | kfree(name); | ||
| 991 | |||
| 992 | if (!dc->debugfs) | ||
| 993 | return -ENOMEM; | ||
| 994 | |||
| 995 | dc->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), | ||
| 996 | GFP_KERNEL); | ||
| 997 | if (!dc->debugfs_files) { | ||
| 998 | err = -ENOMEM; | ||
| 999 | goto remove; | ||
| 1000 | } | ||
| 1001 | |||
| 1002 | for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) | ||
| 1003 | dc->debugfs_files[i].data = dc; | ||
| 1004 | |||
| 1005 | err = drm_debugfs_create_files(dc->debugfs_files, | ||
| 1006 | ARRAY_SIZE(debugfs_files), | ||
| 1007 | dc->debugfs, minor); | ||
| 1008 | if (err < 0) | ||
| 1009 | goto free; | ||
| 1010 | |||
| 1011 | dc->minor = minor; | ||
| 1012 | |||
| 1013 | return 0; | ||
| 1014 | |||
| 1015 | free: | ||
| 1016 | kfree(dc->debugfs_files); | ||
| 1017 | dc->debugfs_files = NULL; | ||
| 1018 | remove: | ||
| 1019 | debugfs_remove(dc->debugfs); | ||
| 1020 | dc->debugfs = NULL; | ||
| 1021 | |||
| 1022 | return err; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | static int tegra_dc_debugfs_exit(struct tegra_dc *dc) | ||
| 1026 | { | ||
| 1027 | drm_debugfs_remove_files(dc->debugfs_files, ARRAY_SIZE(debugfs_files), | ||
| 1028 | dc->minor); | ||
| 1029 | dc->minor = NULL; | ||
| 1030 | |||
| 1031 | kfree(dc->debugfs_files); | ||
| 1032 | dc->debugfs_files = NULL; | ||
| 1033 | |||
| 1034 | debugfs_remove(dc->debugfs); | ||
| 1035 | dc->debugfs = NULL; | ||
| 1036 | |||
| 1037 | return 0; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static int tegra_dc_init(struct host1x_client *client) | ||
| 1041 | { | ||
| 1042 | struct tegra_drm *tegra = dev_get_drvdata(client->parent); | ||
| 1043 | struct tegra_dc *dc = host1x_client_to_dc(client); | ||
| 1044 | int err; | ||
| 1045 | |||
| 1046 | dc->pipe = tegra->drm->mode_config.num_crtc; | ||
| 1047 | |||
| 1048 | drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs); | ||
| 1049 | drm_mode_crtc_set_gamma_size(&dc->base, 256); | ||
| 1050 | drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs); | ||
| 1051 | |||
| 1052 | err = tegra_dc_rgb_init(tegra->drm, dc); | ||
| 1053 | if (err < 0 && err != -ENODEV) { | ||
| 1054 | dev_err(dc->dev, "failed to initialize RGB output: %d\n", err); | ||
| 1055 | return err; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | err = tegra_dc_add_planes(tegra->drm, dc); | ||
| 1059 | if (err < 0) | ||
| 1060 | return err; | ||
| 1061 | |||
| 1062 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
| 1063 | err = tegra_dc_debugfs_init(dc, tegra->drm->primary); | ||
| 1064 | if (err < 0) | ||
| 1065 | dev_err(dc->dev, "debugfs setup failed: %d\n", err); | ||
| 1066 | } | ||
| 1067 | |||
| 1068 | err = devm_request_irq(dc->dev, dc->irq, tegra_dc_irq, 0, | ||
| 1069 | dev_name(dc->dev), dc); | ||
| 1070 | if (err < 0) { | ||
| 1071 | dev_err(dc->dev, "failed to request IRQ#%u: %d\n", dc->irq, | ||
| 1072 | err); | ||
| 1073 | return err; | ||
| 1074 | } | ||
| 1075 | |||
| 1076 | return 0; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | static int tegra_dc_exit(struct host1x_client *client) | ||
| 1080 | { | ||
| 1081 | struct tegra_dc *dc = host1x_client_to_dc(client); | ||
| 1082 | int err; | ||
| 1083 | |||
| 1084 | devm_free_irq(dc->dev, dc->irq, dc); | ||
| 1085 | |||
| 1086 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
| 1087 | err = tegra_dc_debugfs_exit(dc); | ||
| 1088 | if (err < 0) | ||
| 1089 | dev_err(dc->dev, "debugfs cleanup failed: %d\n", err); | ||
| 1090 | } | ||
| 1091 | |||
| 1092 | err = tegra_dc_rgb_exit(dc); | ||
| 1093 | if (err) { | ||
| 1094 | dev_err(dc->dev, "failed to shutdown RGB output: %d\n", err); | ||
| 1095 | return err; | ||
| 1096 | } | ||
| 1097 | |||
| 1098 | return 0; | ||
| 1099 | } | ||
| 1100 | |||
| 1101 | static const struct host1x_client_ops dc_client_ops = { | ||
| 1102 | .init = tegra_dc_init, | ||
| 1103 | .exit = tegra_dc_exit, | ||
| 1104 | }; | ||
| 1105 | |||
| 1106 | static int tegra_dc_probe(struct platform_device *pdev) | ||
| 1107 | { | ||
| 1108 | struct resource *regs; | ||
| 1109 | struct tegra_dc *dc; | ||
| 1110 | int err; | ||
| 1111 | |||
| 1112 | dc = devm_kzalloc(&pdev->dev, sizeof(*dc), GFP_KERNEL); | ||
| 1113 | if (!dc) | ||
| 1114 | return -ENOMEM; | ||
| 1115 | |||
| 1116 | spin_lock_init(&dc->lock); | ||
| 1117 | INIT_LIST_HEAD(&dc->list); | ||
| 1118 | dc->dev = &pdev->dev; | ||
| 1119 | |||
| 1120 | dc->clk = devm_clk_get(&pdev->dev, NULL); | ||
| 1121 | if (IS_ERR(dc->clk)) { | ||
| 1122 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
| 1123 | return PTR_ERR(dc->clk); | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | err = clk_prepare_enable(dc->clk); | ||
| 1127 | if (err < 0) | ||
| 1128 | return err; | ||
| 1129 | |||
| 1130 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 1131 | dc->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
| 1132 | if (IS_ERR(dc->regs)) | ||
| 1133 | return PTR_ERR(dc->regs); | ||
| 1134 | |||
| 1135 | dc->irq = platform_get_irq(pdev, 0); | ||
| 1136 | if (dc->irq < 0) { | ||
| 1137 | dev_err(&pdev->dev, "failed to get IRQ\n"); | ||
| 1138 | return -ENXIO; | ||
| 1139 | } | ||
| 1140 | |||
| 1141 | INIT_LIST_HEAD(&dc->client.list); | ||
| 1142 | dc->client.ops = &dc_client_ops; | ||
| 1143 | dc->client.dev = &pdev->dev; | ||
| 1144 | |||
| 1145 | err = tegra_dc_rgb_probe(dc); | ||
| 1146 | if (err < 0 && err != -ENODEV) { | ||
| 1147 | dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); | ||
| 1148 | return err; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | err = host1x_client_register(&dc->client); | ||
| 1152 | if (err < 0) { | ||
| 1153 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | ||
| 1154 | err); | ||
| 1155 | return err; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | platform_set_drvdata(pdev, dc); | ||
| 1159 | |||
| 1160 | return 0; | ||
| 1161 | } | ||
| 1162 | |||
| 1163 | static int tegra_dc_remove(struct platform_device *pdev) | ||
| 1164 | { | ||
| 1165 | struct tegra_dc *dc = platform_get_drvdata(pdev); | ||
| 1166 | int err; | ||
| 1167 | |||
| 1168 | err = host1x_client_unregister(&dc->client); | ||
| 1169 | if (err < 0) { | ||
| 1170 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | ||
| 1171 | err); | ||
| 1172 | return err; | ||
| 1173 | } | ||
| 1174 | |||
| 1175 | clk_disable_unprepare(dc->clk); | ||
| 1176 | |||
| 1177 | return 0; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static struct of_device_id tegra_dc_of_match[] = { | ||
| 1181 | { .compatible = "nvidia,tegra30-dc", }, | ||
| 1182 | { .compatible = "nvidia,tegra20-dc", }, | ||
| 1183 | { }, | ||
| 1184 | }; | ||
| 1185 | |||
| 1186 | struct platform_driver tegra_dc_driver = { | ||
| 1187 | .driver = { | ||
| 1188 | .name = "tegra-dc", | ||
| 1189 | .owner = THIS_MODULE, | ||
| 1190 | .of_match_table = tegra_dc_of_match, | ||
| 1191 | }, | ||
| 1192 | .probe = tegra_dc_probe, | ||
| 1193 | .remove = tegra_dc_remove, | ||
| 1194 | }; | ||
diff --git a/drivers/gpu/host1x/drm/dc.h b/drivers/gpu/host1x/drm/dc.h deleted file mode 100644 index 79eaec9aac77..000000000000 --- a/drivers/gpu/host1x/drm/dc.h +++ /dev/null | |||
| @@ -1,400 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef TEGRA_DC_H | ||
| 11 | #define TEGRA_DC_H 1 | ||
| 12 | |||
| 13 | #define DC_CMD_GENERAL_INCR_SYNCPT 0x000 | ||
| 14 | #define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001 | ||
| 15 | #define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002 | ||
| 16 | #define DC_CMD_WIN_A_INCR_SYNCPT 0x008 | ||
| 17 | #define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009 | ||
| 18 | #define DC_CMD_WIN_A_INCR_SYNCPT_ERROR 0x00a | ||
| 19 | #define DC_CMD_WIN_B_INCR_SYNCPT 0x010 | ||
| 20 | #define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL 0x011 | ||
| 21 | #define DC_CMD_WIN_B_INCR_SYNCPT_ERROR 0x012 | ||
| 22 | #define DC_CMD_WIN_C_INCR_SYNCPT 0x018 | ||
| 23 | #define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019 | ||
| 24 | #define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a | ||
| 25 | #define DC_CMD_CONT_SYNCPT_VSYNC 0x028 | ||
| 26 | #define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 | ||
| 27 | #define DC_CMD_DISPLAY_COMMAND 0x032 | ||
| 28 | #define DISP_CTRL_MODE_STOP (0 << 5) | ||
| 29 | #define DISP_CTRL_MODE_C_DISPLAY (1 << 5) | ||
| 30 | #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5) | ||
| 31 | #define DC_CMD_SIGNAL_RAISE 0x033 | ||
| 32 | #define DC_CMD_DISPLAY_POWER_CONTROL 0x036 | ||
| 33 | #define PW0_ENABLE (1 << 0) | ||
| 34 | #define PW1_ENABLE (1 << 2) | ||
| 35 | #define PW2_ENABLE (1 << 4) | ||
| 36 | #define PW3_ENABLE (1 << 6) | ||
| 37 | #define PW4_ENABLE (1 << 8) | ||
| 38 | #define PM0_ENABLE (1 << 16) | ||
| 39 | #define PM1_ENABLE (1 << 18) | ||
| 40 | |||
| 41 | #define DC_CMD_INT_STATUS 0x037 | ||
| 42 | #define DC_CMD_INT_MASK 0x038 | ||
| 43 | #define DC_CMD_INT_ENABLE 0x039 | ||
| 44 | #define DC_CMD_INT_TYPE 0x03a | ||
| 45 | #define DC_CMD_INT_POLARITY 0x03b | ||
| 46 | #define CTXSW_INT (1 << 0) | ||
| 47 | #define FRAME_END_INT (1 << 1) | ||
| 48 | #define VBLANK_INT (1 << 2) | ||
| 49 | #define WIN_A_UF_INT (1 << 8) | ||
| 50 | #define WIN_B_UF_INT (1 << 9) | ||
| 51 | #define WIN_C_UF_INT (1 << 10) | ||
| 52 | #define WIN_A_OF_INT (1 << 14) | ||
| 53 | #define WIN_B_OF_INT (1 << 15) | ||
| 54 | #define WIN_C_OF_INT (1 << 16) | ||
| 55 | |||
| 56 | #define DC_CMD_SIGNAL_RAISE1 0x03c | ||
| 57 | #define DC_CMD_SIGNAL_RAISE2 0x03d | ||
| 58 | #define DC_CMD_SIGNAL_RAISE3 0x03e | ||
| 59 | |||
| 60 | #define DC_CMD_STATE_ACCESS 0x040 | ||
| 61 | #define READ_MUX (1 << 0) | ||
| 62 | #define WRITE_MUX (1 << 2) | ||
| 63 | |||
| 64 | #define DC_CMD_STATE_CONTROL 0x041 | ||
| 65 | #define GENERAL_ACT_REQ (1 << 0) | ||
| 66 | #define WIN_A_ACT_REQ (1 << 1) | ||
| 67 | #define WIN_B_ACT_REQ (1 << 2) | ||
| 68 | #define WIN_C_ACT_REQ (1 << 3) | ||
| 69 | #define GENERAL_UPDATE (1 << 8) | ||
| 70 | #define WIN_A_UPDATE (1 << 9) | ||
| 71 | #define WIN_B_UPDATE (1 << 10) | ||
| 72 | #define WIN_C_UPDATE (1 << 11) | ||
| 73 | #define NC_HOST_TRIG (1 << 24) | ||
| 74 | |||
| 75 | #define DC_CMD_DISPLAY_WINDOW_HEADER 0x042 | ||
| 76 | #define WINDOW_A_SELECT (1 << 4) | ||
| 77 | #define WINDOW_B_SELECT (1 << 5) | ||
| 78 | #define WINDOW_C_SELECT (1 << 6) | ||
| 79 | |||
| 80 | #define DC_CMD_REG_ACT_CONTROL 0x043 | ||
| 81 | |||
| 82 | #define DC_COM_CRC_CONTROL 0x300 | ||
| 83 | #define DC_COM_CRC_CHECKSUM 0x301 | ||
| 84 | #define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x)) | ||
| 85 | #define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x)) | ||
| 86 | #define LVS_OUTPUT_POLARITY_LOW (1 << 28) | ||
| 87 | #define LHS_OUTPUT_POLARITY_LOW (1 << 30) | ||
| 88 | #define DC_COM_PIN_OUTPUT_DATA(x) (0x30a + (x)) | ||
| 89 | #define DC_COM_PIN_INPUT_ENABLE(x) (0x30e + (x)) | ||
| 90 | #define DC_COM_PIN_INPUT_DATA(x) (0x312 + (x)) | ||
| 91 | #define DC_COM_PIN_OUTPUT_SELECT(x) (0x314 + (x)) | ||
| 92 | |||
| 93 | #define DC_COM_PIN_MISC_CONTROL 0x31b | ||
| 94 | #define DC_COM_PIN_PM0_CONTROL 0x31c | ||
| 95 | #define DC_COM_PIN_PM0_DUTY_CYCLE 0x31d | ||
| 96 | #define DC_COM_PIN_PM1_CONTROL 0x31e | ||
| 97 | #define DC_COM_PIN_PM1_DUTY_CYCLE 0x31f | ||
| 98 | |||
| 99 | #define DC_COM_SPI_CONTROL 0x320 | ||
| 100 | #define DC_COM_SPI_START_BYTE 0x321 | ||
| 101 | #define DC_COM_HSPI_WRITE_DATA_AB 0x322 | ||
| 102 | #define DC_COM_HSPI_WRITE_DATA_CD 0x323 | ||
| 103 | #define DC_COM_HSPI_CS_DC 0x324 | ||
| 104 | #define DC_COM_SCRATCH_REGISTER_A 0x325 | ||
| 105 | #define DC_COM_SCRATCH_REGISTER_B 0x326 | ||
| 106 | #define DC_COM_GPIO_CTRL 0x327 | ||
| 107 | #define DC_COM_GPIO_DEBOUNCE_COUNTER 0x328 | ||
| 108 | #define DC_COM_CRC_CHECKSUM_LATCHED 0x329 | ||
| 109 | |||
| 110 | #define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400 | ||
| 111 | #define H_PULSE_0_ENABLE (1 << 8) | ||
| 112 | #define H_PULSE_1_ENABLE (1 << 10) | ||
| 113 | #define H_PULSE_2_ENABLE (1 << 12) | ||
| 114 | |||
| 115 | #define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401 | ||
| 116 | |||
| 117 | #define DC_DISP_DISP_WIN_OPTIONS 0x402 | ||
| 118 | #define HDMI_ENABLE (1 << 30) | ||
| 119 | |||
| 120 | #define DC_DISP_DISP_MEM_HIGH_PRIORITY 0x403 | ||
| 121 | #define CURSOR_THRESHOLD(x) (((x) & 0x03) << 24) | ||
| 122 | #define WINDOW_A_THRESHOLD(x) (((x) & 0x7f) << 16) | ||
| 123 | #define WINDOW_B_THRESHOLD(x) (((x) & 0x7f) << 8) | ||
| 124 | #define WINDOW_C_THRESHOLD(x) (((x) & 0xff) << 0) | ||
| 125 | |||
| 126 | #define DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER 0x404 | ||
| 127 | #define CURSOR_DELAY(x) (((x) & 0x3f) << 24) | ||
| 128 | #define WINDOW_A_DELAY(x) (((x) & 0x3f) << 16) | ||
| 129 | #define WINDOW_B_DELAY(x) (((x) & 0x3f) << 8) | ||
| 130 | #define WINDOW_C_DELAY(x) (((x) & 0x3f) << 0) | ||
| 131 | |||
| 132 | #define DC_DISP_DISP_TIMING_OPTIONS 0x405 | ||
| 133 | #define VSYNC_H_POSITION(x) ((x) & 0xfff) | ||
| 134 | |||
| 135 | #define DC_DISP_REF_TO_SYNC 0x406 | ||
| 136 | #define DC_DISP_SYNC_WIDTH 0x407 | ||
| 137 | #define DC_DISP_BACK_PORCH 0x408 | ||
| 138 | #define DC_DISP_ACTIVE 0x409 | ||
| 139 | #define DC_DISP_FRONT_PORCH 0x40a | ||
| 140 | #define DC_DISP_H_PULSE0_CONTROL 0x40b | ||
| 141 | #define DC_DISP_H_PULSE0_POSITION_A 0x40c | ||
| 142 | #define DC_DISP_H_PULSE0_POSITION_B 0x40d | ||
| 143 | #define DC_DISP_H_PULSE0_POSITION_C 0x40e | ||
| 144 | #define DC_DISP_H_PULSE0_POSITION_D 0x40f | ||
| 145 | #define DC_DISP_H_PULSE1_CONTROL 0x410 | ||
| 146 | #define DC_DISP_H_PULSE1_POSITION_A 0x411 | ||
| 147 | #define DC_DISP_H_PULSE1_POSITION_B 0x412 | ||
| 148 | #define DC_DISP_H_PULSE1_POSITION_C 0x413 | ||
| 149 | #define DC_DISP_H_PULSE1_POSITION_D 0x414 | ||
| 150 | #define DC_DISP_H_PULSE2_CONTROL 0x415 | ||
| 151 | #define DC_DISP_H_PULSE2_POSITION_A 0x416 | ||
| 152 | #define DC_DISP_H_PULSE2_POSITION_B 0x417 | ||
| 153 | #define DC_DISP_H_PULSE2_POSITION_C 0x418 | ||
| 154 | #define DC_DISP_H_PULSE2_POSITION_D 0x419 | ||
| 155 | #define DC_DISP_V_PULSE0_CONTROL 0x41a | ||
| 156 | #define DC_DISP_V_PULSE0_POSITION_A 0x41b | ||
| 157 | #define DC_DISP_V_PULSE0_POSITION_B 0x41c | ||
| 158 | #define DC_DISP_V_PULSE0_POSITION_C 0x41d | ||
| 159 | #define DC_DISP_V_PULSE1_CONTROL 0x41e | ||
| 160 | #define DC_DISP_V_PULSE1_POSITION_A 0x41f | ||
| 161 | #define DC_DISP_V_PULSE1_POSITION_B 0x420 | ||
| 162 | #define DC_DISP_V_PULSE1_POSITION_C 0x421 | ||
| 163 | #define DC_DISP_V_PULSE2_CONTROL 0x422 | ||
| 164 | #define DC_DISP_V_PULSE2_POSITION_A 0x423 | ||
| 165 | #define DC_DISP_V_PULSE3_CONTROL 0x424 | ||
| 166 | #define DC_DISP_V_PULSE3_POSITION_A 0x425 | ||
| 167 | #define DC_DISP_M0_CONTROL 0x426 | ||
| 168 | #define DC_DISP_M1_CONTROL 0x427 | ||
| 169 | #define DC_DISP_DI_CONTROL 0x428 | ||
| 170 | #define DC_DISP_PP_CONTROL 0x429 | ||
| 171 | #define DC_DISP_PP_SELECT_A 0x42a | ||
| 172 | #define DC_DISP_PP_SELECT_B 0x42b | ||
| 173 | #define DC_DISP_PP_SELECT_C 0x42c | ||
| 174 | #define DC_DISP_PP_SELECT_D 0x42d | ||
| 175 | |||
| 176 | #define PULSE_MODE_NORMAL (0 << 3) | ||
| 177 | #define PULSE_MODE_ONE_CLOCK (1 << 3) | ||
| 178 | #define PULSE_POLARITY_HIGH (0 << 4) | ||
| 179 | #define PULSE_POLARITY_LOW (1 << 4) | ||
| 180 | #define PULSE_QUAL_ALWAYS (0 << 6) | ||
| 181 | #define PULSE_QUAL_VACTIVE (2 << 6) | ||
| 182 | #define PULSE_QUAL_VACTIVE1 (3 << 6) | ||
| 183 | #define PULSE_LAST_START_A (0 << 8) | ||
| 184 | #define PULSE_LAST_END_A (1 << 8) | ||
| 185 | #define PULSE_LAST_START_B (2 << 8) | ||
| 186 | #define PULSE_LAST_END_B (3 << 8) | ||
| 187 | #define PULSE_LAST_START_C (4 << 8) | ||
| 188 | #define PULSE_LAST_END_C (5 << 8) | ||
| 189 | #define PULSE_LAST_START_D (6 << 8) | ||
| 190 | #define PULSE_LAST_END_D (7 << 8) | ||
| 191 | |||
| 192 | #define PULSE_START(x) (((x) & 0xfff) << 0) | ||
| 193 | #define PULSE_END(x) (((x) & 0xfff) << 16) | ||
| 194 | |||
| 195 | #define DC_DISP_DISP_CLOCK_CONTROL 0x42e | ||
| 196 | #define PIXEL_CLK_DIVIDER_PCD1 (0 << 8) | ||
| 197 | #define PIXEL_CLK_DIVIDER_PCD1H (1 << 8) | ||
| 198 | #define PIXEL_CLK_DIVIDER_PCD2 (2 << 8) | ||
| 199 | #define PIXEL_CLK_DIVIDER_PCD3 (3 << 8) | ||
| 200 | #define PIXEL_CLK_DIVIDER_PCD4 (4 << 8) | ||
| 201 | #define PIXEL_CLK_DIVIDER_PCD6 (5 << 8) | ||
| 202 | #define PIXEL_CLK_DIVIDER_PCD8 (6 << 8) | ||
| 203 | #define PIXEL_CLK_DIVIDER_PCD9 (7 << 8) | ||
| 204 | #define PIXEL_CLK_DIVIDER_PCD12 (8 << 8) | ||
| 205 | #define PIXEL_CLK_DIVIDER_PCD16 (9 << 8) | ||
| 206 | #define PIXEL_CLK_DIVIDER_PCD18 (10 << 8) | ||
| 207 | #define PIXEL_CLK_DIVIDER_PCD24 (11 << 8) | ||
| 208 | #define PIXEL_CLK_DIVIDER_PCD13 (12 << 8) | ||
| 209 | #define SHIFT_CLK_DIVIDER(x) ((x) & 0xff) | ||
| 210 | |||
| 211 | #define DC_DISP_DISP_INTERFACE_CONTROL 0x42f | ||
| 212 | #define DISP_DATA_FORMAT_DF1P1C (0 << 0) | ||
| 213 | #define DISP_DATA_FORMAT_DF1P2C24B (1 << 0) | ||
| 214 | #define DISP_DATA_FORMAT_DF1P2C18B (2 << 0) | ||
| 215 | #define DISP_DATA_FORMAT_DF1P2C16B (3 << 0) | ||
| 216 | #define DISP_DATA_FORMAT_DF2S (4 << 0) | ||
| 217 | #define DISP_DATA_FORMAT_DF3S (5 << 0) | ||
| 218 | #define DISP_DATA_FORMAT_DFSPI (6 << 0) | ||
| 219 | #define DISP_DATA_FORMAT_DF1P3C24B (7 << 0) | ||
| 220 | #define DISP_DATA_FORMAT_DF1P3C18B (8 << 0) | ||
| 221 | #define DISP_ALIGNMENT_MSB (0 << 8) | ||
| 222 | #define DISP_ALIGNMENT_LSB (1 << 8) | ||
| 223 | #define DISP_ORDER_RED_BLUE (0 << 9) | ||
| 224 | #define DISP_ORDER_BLUE_RED (1 << 9) | ||
| 225 | |||
| 226 | #define DC_DISP_DISP_COLOR_CONTROL 0x430 | ||
| 227 | #define BASE_COLOR_SIZE666 (0 << 0) | ||
| 228 | #define BASE_COLOR_SIZE111 (1 << 0) | ||
| 229 | #define BASE_COLOR_SIZE222 (2 << 0) | ||
| 230 | #define BASE_COLOR_SIZE333 (3 << 0) | ||
| 231 | #define BASE_COLOR_SIZE444 (4 << 0) | ||
| 232 | #define BASE_COLOR_SIZE555 (5 << 0) | ||
| 233 | #define BASE_COLOR_SIZE565 (6 << 0) | ||
| 234 | #define BASE_COLOR_SIZE332 (7 << 0) | ||
| 235 | #define BASE_COLOR_SIZE888 (8 << 0) | ||
| 236 | #define DITHER_CONTROL_DISABLE (0 << 8) | ||
| 237 | #define DITHER_CONTROL_ORDERED (2 << 8) | ||
| 238 | #define DITHER_CONTROL_ERRDIFF (3 << 8) | ||
| 239 | |||
| 240 | #define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431 | ||
| 241 | |||
| 242 | #define DC_DISP_DATA_ENABLE_OPTIONS 0x432 | ||
| 243 | #define DE_SELECT_ACTIVE_BLANK (0 << 0) | ||
| 244 | #define DE_SELECT_ACTIVE (1 << 0) | ||
| 245 | #define DE_SELECT_ACTIVE_IS (2 << 0) | ||
| 246 | #define DE_CONTROL_ONECLK (0 << 2) | ||
| 247 | #define DE_CONTROL_NORMAL (1 << 2) | ||
| 248 | #define DE_CONTROL_EARLY_EXT (2 << 2) | ||
| 249 | #define DE_CONTROL_EARLY (3 << 2) | ||
| 250 | #define DE_CONTROL_ACTIVE_BLANK (4 << 2) | ||
| 251 | |||
| 252 | #define DC_DISP_SERIAL_INTERFACE_OPTIONS 0x433 | ||
| 253 | #define DC_DISP_LCD_SPI_OPTIONS 0x434 | ||
| 254 | #define DC_DISP_BORDER_COLOR 0x435 | ||
| 255 | #define DC_DISP_COLOR_KEY0_LOWER 0x436 | ||
| 256 | #define DC_DISP_COLOR_KEY0_UPPER 0x437 | ||
| 257 | #define DC_DISP_COLOR_KEY1_LOWER 0x438 | ||
| 258 | #define DC_DISP_COLOR_KEY1_UPPER 0x439 | ||
| 259 | |||
| 260 | #define DC_DISP_CURSOR_FOREGROUND 0x43c | ||
| 261 | #define DC_DISP_CURSOR_BACKGROUND 0x43d | ||
| 262 | |||
| 263 | #define DC_DISP_CURSOR_START_ADDR 0x43e | ||
| 264 | #define DC_DISP_CURSOR_START_ADDR_NS 0x43f | ||
| 265 | |||
| 266 | #define DC_DISP_CURSOR_POSITION 0x440 | ||
| 267 | #define DC_DISP_CURSOR_POSITION_NS 0x441 | ||
| 268 | |||
| 269 | #define DC_DISP_INIT_SEQ_CONTROL 0x442 | ||
| 270 | #define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443 | ||
| 271 | #define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444 | ||
| 272 | #define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445 | ||
| 273 | #define DC_DISP_SPI_INIT_SEQ_DATA_D 0x446 | ||
| 274 | |||
| 275 | #define DC_DISP_DC_MCCIF_FIFOCTRL 0x480 | ||
| 276 | #define DC_DISP_MCCIF_DISPLAY0A_HYST 0x481 | ||
| 277 | #define DC_DISP_MCCIF_DISPLAY0B_HYST 0x482 | ||
| 278 | #define DC_DISP_MCCIF_DISPLAY1A_HYST 0x483 | ||
| 279 | #define DC_DISP_MCCIF_DISPLAY1B_HYST 0x484 | ||
| 280 | |||
| 281 | #define DC_DISP_DAC_CRT_CTRL 0x4c0 | ||
| 282 | #define DC_DISP_DISP_MISC_CONTROL 0x4c1 | ||
| 283 | #define DC_DISP_SD_CONTROL 0x4c2 | ||
| 284 | #define DC_DISP_SD_CSC_COEFF 0x4c3 | ||
| 285 | #define DC_DISP_SD_LUT(x) (0x4c4 + (x)) | ||
| 286 | #define DC_DISP_SD_FLICKER_CONTROL 0x4cd | ||
| 287 | #define DC_DISP_DC_PIXEL_COUNT 0x4ce | ||
| 288 | #define DC_DISP_SD_HISTOGRAM(x) (0x4cf + (x)) | ||
| 289 | #define DC_DISP_SD_BL_PARAMETERS 0x4d7 | ||
| 290 | #define DC_DISP_SD_BL_TF(x) (0x4d8 + (x)) | ||
| 291 | #define DC_DISP_SD_BL_CONTROL 0x4dc | ||
| 292 | #define DC_DISP_SD_HW_K_VALUES 0x4dd | ||
| 293 | #define DC_DISP_SD_MAN_K_VALUES 0x4de | ||
| 294 | |||
| 295 | #define DC_WIN_CSC_YOF 0x611 | ||
| 296 | #define DC_WIN_CSC_KYRGB 0x612 | ||
| 297 | #define DC_WIN_CSC_KUR 0x613 | ||
| 298 | #define DC_WIN_CSC_KVR 0x614 | ||
| 299 | #define DC_WIN_CSC_KUG 0x615 | ||
| 300 | #define DC_WIN_CSC_KVG 0x616 | ||
| 301 | #define DC_WIN_CSC_KUB 0x617 | ||
| 302 | #define DC_WIN_CSC_KVB 0x618 | ||
| 303 | |||
| 304 | #define DC_WIN_WIN_OPTIONS 0x700 | ||
| 305 | #define COLOR_EXPAND (1 << 6) | ||
| 306 | #define CSC_ENABLE (1 << 18) | ||
| 307 | #define WIN_ENABLE (1 << 30) | ||
| 308 | |||
| 309 | #define DC_WIN_BYTE_SWAP 0x701 | ||
| 310 | #define BYTE_SWAP_NOSWAP (0 << 0) | ||
| 311 | #define BYTE_SWAP_SWAP2 (1 << 0) | ||
| 312 | #define BYTE_SWAP_SWAP4 (2 << 0) | ||
| 313 | #define BYTE_SWAP_SWAP4HW (3 << 0) | ||
| 314 | |||
| 315 | #define DC_WIN_BUFFER_CONTROL 0x702 | ||
| 316 | #define BUFFER_CONTROL_HOST (0 << 0) | ||
| 317 | #define BUFFER_CONTROL_VI (1 << 0) | ||
| 318 | #define BUFFER_CONTROL_EPP (2 << 0) | ||
| 319 | #define BUFFER_CONTROL_MPEGE (3 << 0) | ||
| 320 | #define BUFFER_CONTROL_SB2D (4 << 0) | ||
| 321 | |||
| 322 | #define DC_WIN_COLOR_DEPTH 0x703 | ||
| 323 | #define WIN_COLOR_DEPTH_P1 0 | ||
| 324 | #define WIN_COLOR_DEPTH_P2 1 | ||
| 325 | #define WIN_COLOR_DEPTH_P4 2 | ||
| 326 | #define WIN_COLOR_DEPTH_P8 3 | ||
| 327 | #define WIN_COLOR_DEPTH_B4G4R4A4 4 | ||
| 328 | #define WIN_COLOR_DEPTH_B5G5R5A 5 | ||
| 329 | #define WIN_COLOR_DEPTH_B5G6R5 6 | ||
| 330 | #define WIN_COLOR_DEPTH_AB5G5R5 7 | ||
| 331 | #define WIN_COLOR_DEPTH_B8G8R8A8 12 | ||
| 332 | #define WIN_COLOR_DEPTH_R8G8B8A8 13 | ||
| 333 | #define WIN_COLOR_DEPTH_B6x2G6x2R6x2A8 14 | ||
| 334 | #define WIN_COLOR_DEPTH_R6x2G6x2B6x2A8 15 | ||
| 335 | #define WIN_COLOR_DEPTH_YCbCr422 16 | ||
| 336 | #define WIN_COLOR_DEPTH_YUV422 17 | ||
| 337 | #define WIN_COLOR_DEPTH_YCbCr420P 18 | ||
| 338 | #define WIN_COLOR_DEPTH_YUV420P 19 | ||
| 339 | #define WIN_COLOR_DEPTH_YCbCr422P 20 | ||
| 340 | #define WIN_COLOR_DEPTH_YUV422P 21 | ||
| 341 | #define WIN_COLOR_DEPTH_YCbCr422R 22 | ||
| 342 | #define WIN_COLOR_DEPTH_YUV422R 23 | ||
| 343 | #define WIN_COLOR_DEPTH_YCbCr422RA 24 | ||
| 344 | #define WIN_COLOR_DEPTH_YUV422RA 25 | ||
| 345 | |||
| 346 | #define DC_WIN_POSITION 0x704 | ||
| 347 | #define H_POSITION(x) (((x) & 0x1fff) << 0) | ||
| 348 | #define V_POSITION(x) (((x) & 0x1fff) << 16) | ||
| 349 | |||
| 350 | #define DC_WIN_SIZE 0x705 | ||
| 351 | #define H_SIZE(x) (((x) & 0x1fff) << 0) | ||
| 352 | #define V_SIZE(x) (((x) & 0x1fff) << 16) | ||
| 353 | |||
| 354 | #define DC_WIN_PRESCALED_SIZE 0x706 | ||
| 355 | #define H_PRESCALED_SIZE(x) (((x) & 0x7fff) << 0) | ||
| 356 | #define V_PRESCALED_SIZE(x) (((x) & 0x1fff) << 16) | ||
| 357 | |||
| 358 | #define DC_WIN_H_INITIAL_DDA 0x707 | ||
| 359 | #define DC_WIN_V_INITIAL_DDA 0x708 | ||
| 360 | #define DC_WIN_DDA_INC 0x709 | ||
| 361 | #define H_DDA_INC(x) (((x) & 0xffff) << 0) | ||
| 362 | #define V_DDA_INC(x) (((x) & 0xffff) << 16) | ||
| 363 | |||
| 364 | #define DC_WIN_LINE_STRIDE 0x70a | ||
| 365 | #define DC_WIN_BUF_STRIDE 0x70b | ||
| 366 | #define DC_WIN_UV_BUF_STRIDE 0x70c | ||
| 367 | #define DC_WIN_BUFFER_ADDR_MODE 0x70d | ||
| 368 | #define DC_WIN_DV_CONTROL 0x70e | ||
| 369 | |||
| 370 | #define DC_WIN_BLEND_NOKEY 0x70f | ||
| 371 | #define DC_WIN_BLEND_1WIN 0x710 | ||
| 372 | #define DC_WIN_BLEND_2WIN_X 0x711 | ||
| 373 | #define DC_WIN_BLEND_2WIN_Y 0x712 | ||
| 374 | #define DC_WIN_BLEND_3WIN_XY 0x713 | ||
| 375 | |||
| 376 | #define DC_WIN_HP_FETCH_CONTROL 0x714 | ||
| 377 | |||
| 378 | #define DC_WINBUF_START_ADDR 0x800 | ||
| 379 | #define DC_WINBUF_START_ADDR_NS 0x801 | ||
| 380 | #define DC_WINBUF_START_ADDR_U 0x802 | ||
| 381 | #define DC_WINBUF_START_ADDR_U_NS 0x803 | ||
| 382 | #define DC_WINBUF_START_ADDR_V 0x804 | ||
| 383 | #define DC_WINBUF_START_ADDR_V_NS 0x805 | ||
| 384 | |||
| 385 | #define DC_WINBUF_ADDR_H_OFFSET 0x806 | ||
| 386 | #define DC_WINBUF_ADDR_H_OFFSET_NS 0x807 | ||
| 387 | #define DC_WINBUF_ADDR_V_OFFSET 0x808 | ||
| 388 | #define DC_WINBUF_ADDR_V_OFFSET_NS 0x809 | ||
| 389 | |||
| 390 | #define DC_WINBUF_UFLOW_STATUS 0x80a | ||
| 391 | |||
| 392 | #define DC_WINBUF_AD_UFLOW_STATUS 0xbca | ||
| 393 | #define DC_WINBUF_BD_UFLOW_STATUS 0xdca | ||
| 394 | #define DC_WINBUF_CD_UFLOW_STATUS 0xfca | ||
| 395 | |||
| 396 | /* synchronization points */ | ||
| 397 | #define SYNCPT_VBLANK0 26 | ||
| 398 | #define SYNCPT_VBLANK1 27 | ||
| 399 | |||
| 400 | #endif /* TEGRA_DC_H */ | ||
diff --git a/drivers/gpu/host1x/drm/drm.c b/drivers/gpu/host1x/drm/drm.c deleted file mode 100644 index c2db409bbd63..000000000000 --- a/drivers/gpu/host1x/drm/drm.c +++ /dev/null | |||
| @@ -1,545 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/host1x.h> | ||
| 11 | |||
| 12 | #include "drm.h" | ||
| 13 | #include "gem.h" | ||
| 14 | |||
| 15 | #define DRIVER_NAME "tegra" | ||
| 16 | #define DRIVER_DESC "NVIDIA Tegra graphics" | ||
| 17 | #define DRIVER_DATE "20120330" | ||
| 18 | #define DRIVER_MAJOR 0 | ||
| 19 | #define DRIVER_MINOR 0 | ||
| 20 | #define DRIVER_PATCHLEVEL 0 | ||
| 21 | |||
| 22 | struct tegra_drm_file { | ||
| 23 | struct list_head contexts; | ||
| 24 | }; | ||
| 25 | |||
| 26 | static int tegra_drm_load(struct drm_device *drm, unsigned long flags) | ||
| 27 | { | ||
| 28 | struct host1x_device *device = to_host1x_device(drm->dev); | ||
| 29 | struct tegra_drm *tegra; | ||
| 30 | int err; | ||
| 31 | |||
| 32 | tegra = kzalloc(sizeof(*tegra), GFP_KERNEL); | ||
| 33 | if (!tegra) | ||
| 34 | return -ENOMEM; | ||
| 35 | |||
| 36 | dev_set_drvdata(drm->dev, tegra); | ||
| 37 | mutex_init(&tegra->clients_lock); | ||
| 38 | INIT_LIST_HEAD(&tegra->clients); | ||
| 39 | drm->dev_private = tegra; | ||
| 40 | tegra->drm = drm; | ||
| 41 | |||
| 42 | drm_mode_config_init(drm); | ||
| 43 | |||
| 44 | err = host1x_device_init(device); | ||
| 45 | if (err < 0) | ||
| 46 | return err; | ||
| 47 | |||
| 48 | /* | ||
| 49 | * We don't use the drm_irq_install() helpers provided by the DRM | ||
| 50 | * core, so we need to set this manually in order to allow the | ||
| 51 | * DRM_IOCTL_WAIT_VBLANK to operate correctly. | ||
| 52 | */ | ||
| 53 | drm->irq_enabled = true; | ||
| 54 | |||
| 55 | err = drm_vblank_init(drm, drm->mode_config.num_crtc); | ||
| 56 | if (err < 0) | ||
| 57 | return err; | ||
| 58 | |||
| 59 | err = tegra_drm_fb_init(drm); | ||
| 60 | if (err < 0) | ||
| 61 | return err; | ||
| 62 | |||
| 63 | drm_kms_helper_poll_init(drm); | ||
| 64 | |||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | |||
| 68 | static int tegra_drm_unload(struct drm_device *drm) | ||
| 69 | { | ||
| 70 | struct host1x_device *device = to_host1x_device(drm->dev); | ||
| 71 | int err; | ||
| 72 | |||
| 73 | drm_kms_helper_poll_fini(drm); | ||
| 74 | tegra_drm_fb_exit(drm); | ||
| 75 | |||
| 76 | err = host1x_device_exit(device); | ||
| 77 | if (err < 0) | ||
| 78 | return err; | ||
| 79 | |||
| 80 | drm_mode_config_cleanup(drm); | ||
| 81 | |||
| 82 | return 0; | ||
| 83 | } | ||
| 84 | |||
| 85 | static int tegra_drm_open(struct drm_device *drm, struct drm_file *filp) | ||
| 86 | { | ||
| 87 | struct tegra_drm_file *fpriv; | ||
| 88 | |||
| 89 | fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); | ||
| 90 | if (!fpriv) | ||
| 91 | return -ENOMEM; | ||
| 92 | |||
| 93 | INIT_LIST_HEAD(&fpriv->contexts); | ||
| 94 | filp->driver_priv = fpriv; | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static void tegra_drm_context_free(struct tegra_drm_context *context) | ||
| 100 | { | ||
| 101 | context->client->ops->close_channel(context); | ||
| 102 | kfree(context); | ||
| 103 | } | ||
| 104 | |||
| 105 | static void tegra_drm_lastclose(struct drm_device *drm) | ||
| 106 | { | ||
| 107 | struct tegra_drm *tegra = drm->dev_private; | ||
| 108 | |||
| 109 | tegra_fbdev_restore_mode(tegra->fbdev); | ||
| 110 | } | ||
| 111 | |||
| 112 | #ifdef CONFIG_DRM_TEGRA_STAGING | ||
| 113 | static struct tegra_drm_context *tegra_drm_get_context(__u64 context) | ||
| 114 | { | ||
| 115 | return (struct tegra_drm_context *)(uintptr_t)context; | ||
| 116 | } | ||
| 117 | |||
| 118 | static bool tegra_drm_file_owns_context(struct tegra_drm_file *file, | ||
| 119 | struct tegra_drm_context *context) | ||
| 120 | { | ||
| 121 | struct tegra_drm_context *ctx; | ||
| 122 | |||
| 123 | list_for_each_entry(ctx, &file->contexts, list) | ||
| 124 | if (ctx == context) | ||
| 125 | return true; | ||
| 126 | |||
| 127 | return false; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int tegra_gem_create(struct drm_device *drm, void *data, | ||
| 131 | struct drm_file *file) | ||
| 132 | { | ||
| 133 | struct drm_tegra_gem_create *args = data; | ||
| 134 | struct tegra_bo *bo; | ||
| 135 | |||
| 136 | bo = tegra_bo_create_with_handle(file, drm, args->size, | ||
| 137 | &args->handle); | ||
| 138 | if (IS_ERR(bo)) | ||
| 139 | return PTR_ERR(bo); | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | |||
| 144 | static int tegra_gem_mmap(struct drm_device *drm, void *data, | ||
| 145 | struct drm_file *file) | ||
| 146 | { | ||
| 147 | struct drm_tegra_gem_mmap *args = data; | ||
| 148 | struct drm_gem_object *gem; | ||
| 149 | struct tegra_bo *bo; | ||
| 150 | |||
| 151 | gem = drm_gem_object_lookup(drm, file, args->handle); | ||
| 152 | if (!gem) | ||
| 153 | return -EINVAL; | ||
| 154 | |||
| 155 | bo = to_tegra_bo(gem); | ||
| 156 | |||
| 157 | args->offset = drm_vma_node_offset_addr(&bo->gem.vma_node); | ||
| 158 | |||
| 159 | drm_gem_object_unreference(gem); | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | static int tegra_syncpt_read(struct drm_device *drm, void *data, | ||
| 165 | struct drm_file *file) | ||
| 166 | { | ||
| 167 | struct host1x *host = dev_get_drvdata(drm->dev->parent); | ||
| 168 | struct drm_tegra_syncpt_read *args = data; | ||
| 169 | struct host1x_syncpt *sp; | ||
| 170 | |||
| 171 | sp = host1x_syncpt_get(host, args->id); | ||
| 172 | if (!sp) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | args->value = host1x_syncpt_read_min(sp); | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | static int tegra_syncpt_incr(struct drm_device *drm, void *data, | ||
| 180 | struct drm_file *file) | ||
| 181 | { | ||
| 182 | struct host1x *host1x = dev_get_drvdata(drm->dev->parent); | ||
| 183 | struct drm_tegra_syncpt_incr *args = data; | ||
| 184 | struct host1x_syncpt *sp; | ||
| 185 | |||
| 186 | sp = host1x_syncpt_get(host1x, args->id); | ||
| 187 | if (!sp) | ||
| 188 | return -EINVAL; | ||
| 189 | |||
| 190 | return host1x_syncpt_incr(sp); | ||
| 191 | } | ||
| 192 | |||
| 193 | static int tegra_syncpt_wait(struct drm_device *drm, void *data, | ||
| 194 | struct drm_file *file) | ||
| 195 | { | ||
| 196 | struct host1x *host1x = dev_get_drvdata(drm->dev->parent); | ||
| 197 | struct drm_tegra_syncpt_wait *args = data; | ||
| 198 | struct host1x_syncpt *sp; | ||
| 199 | |||
| 200 | sp = host1x_syncpt_get(host1x, args->id); | ||
| 201 | if (!sp) | ||
| 202 | return -EINVAL; | ||
| 203 | |||
| 204 | return host1x_syncpt_wait(sp, args->thresh, args->timeout, | ||
| 205 | &args->value); | ||
| 206 | } | ||
| 207 | |||
| 208 | static int tegra_open_channel(struct drm_device *drm, void *data, | ||
| 209 | struct drm_file *file) | ||
| 210 | { | ||
| 211 | struct tegra_drm_file *fpriv = file->driver_priv; | ||
| 212 | struct tegra_drm *tegra = drm->dev_private; | ||
| 213 | struct drm_tegra_open_channel *args = data; | ||
| 214 | struct tegra_drm_context *context; | ||
| 215 | struct tegra_drm_client *client; | ||
| 216 | int err = -ENODEV; | ||
| 217 | |||
| 218 | context = kzalloc(sizeof(*context), GFP_KERNEL); | ||
| 219 | if (!context) | ||
| 220 | return -ENOMEM; | ||
| 221 | |||
| 222 | list_for_each_entry(client, &tegra->clients, list) | ||
| 223 | if (client->base.class == args->client) { | ||
| 224 | err = client->ops->open_channel(client, context); | ||
| 225 | if (err) | ||
| 226 | break; | ||
| 227 | |||
| 228 | list_add(&context->list, &fpriv->contexts); | ||
| 229 | args->context = (uintptr_t)context; | ||
| 230 | context->client = client; | ||
| 231 | return 0; | ||
| 232 | } | ||
| 233 | |||
| 234 | kfree(context); | ||
| 235 | return err; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int tegra_close_channel(struct drm_device *drm, void *data, | ||
| 239 | struct drm_file *file) | ||
| 240 | { | ||
| 241 | struct tegra_drm_file *fpriv = file->driver_priv; | ||
| 242 | struct drm_tegra_close_channel *args = data; | ||
| 243 | struct tegra_drm_context *context; | ||
| 244 | |||
| 245 | context = tegra_drm_get_context(args->context); | ||
| 246 | |||
| 247 | if (!tegra_drm_file_owns_context(fpriv, context)) | ||
| 248 | return -EINVAL; | ||
| 249 | |||
| 250 | list_del(&context->list); | ||
| 251 | tegra_drm_context_free(context); | ||
| 252 | |||
| 253 | return 0; | ||
| 254 | } | ||
| 255 | |||
| 256 | static int tegra_get_syncpt(struct drm_device *drm, void *data, | ||
| 257 | struct drm_file *file) | ||
| 258 | { | ||
| 259 | struct tegra_drm_file *fpriv = file->driver_priv; | ||
| 260 | struct drm_tegra_get_syncpt *args = data; | ||
| 261 | struct tegra_drm_context *context; | ||
| 262 | struct host1x_syncpt *syncpt; | ||
| 263 | |||
| 264 | context = tegra_drm_get_context(args->context); | ||
| 265 | |||
| 266 | if (!tegra_drm_file_owns_context(fpriv, context)) | ||
| 267 | return -ENODEV; | ||
| 268 | |||
| 269 | if (args->index >= context->client->base.num_syncpts) | ||
| 270 | return -EINVAL; | ||
| 271 | |||
| 272 | syncpt = context->client->base.syncpts[args->index]; | ||
| 273 | args->id = host1x_syncpt_id(syncpt); | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | static int tegra_submit(struct drm_device *drm, void *data, | ||
| 279 | struct drm_file *file) | ||
| 280 | { | ||
| 281 | struct tegra_drm_file *fpriv = file->driver_priv; | ||
| 282 | struct drm_tegra_submit *args = data; | ||
| 283 | struct tegra_drm_context *context; | ||
| 284 | |||
| 285 | context = tegra_drm_get_context(args->context); | ||
| 286 | |||
| 287 | if (!tegra_drm_file_owns_context(fpriv, context)) | ||
| 288 | return -ENODEV; | ||
| 289 | |||
| 290 | return context->client->ops->submit(context, args, drm, file); | ||
| 291 | } | ||
| 292 | #endif | ||
| 293 | |||
| 294 | static const struct drm_ioctl_desc tegra_drm_ioctls[] = { | ||
| 295 | #ifdef CONFIG_DRM_TEGRA_STAGING | ||
| 296 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_CREATE, tegra_gem_create, DRM_UNLOCKED | DRM_AUTH), | ||
| 297 | DRM_IOCTL_DEF_DRV(TEGRA_GEM_MMAP, tegra_gem_mmap, DRM_UNLOCKED), | ||
| 298 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_READ, tegra_syncpt_read, DRM_UNLOCKED), | ||
| 299 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_INCR, tegra_syncpt_incr, DRM_UNLOCKED), | ||
| 300 | DRM_IOCTL_DEF_DRV(TEGRA_SYNCPT_WAIT, tegra_syncpt_wait, DRM_UNLOCKED), | ||
| 301 | DRM_IOCTL_DEF_DRV(TEGRA_OPEN_CHANNEL, tegra_open_channel, DRM_UNLOCKED), | ||
| 302 | DRM_IOCTL_DEF_DRV(TEGRA_CLOSE_CHANNEL, tegra_close_channel, DRM_UNLOCKED), | ||
| 303 | DRM_IOCTL_DEF_DRV(TEGRA_GET_SYNCPT, tegra_get_syncpt, DRM_UNLOCKED), | ||
| 304 | DRM_IOCTL_DEF_DRV(TEGRA_SUBMIT, tegra_submit, DRM_UNLOCKED), | ||
| 305 | #endif | ||
| 306 | }; | ||
| 307 | |||
| 308 | static const struct file_operations tegra_drm_fops = { | ||
| 309 | .owner = THIS_MODULE, | ||
| 310 | .open = drm_open, | ||
| 311 | .release = drm_release, | ||
| 312 | .unlocked_ioctl = drm_ioctl, | ||
| 313 | .mmap = tegra_drm_mmap, | ||
| 314 | .poll = drm_poll, | ||
| 315 | .read = drm_read, | ||
| 316 | #ifdef CONFIG_COMPAT | ||
| 317 | .compat_ioctl = drm_compat_ioctl, | ||
| 318 | #endif | ||
| 319 | .llseek = noop_llseek, | ||
| 320 | }; | ||
| 321 | |||
| 322 | static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm, int pipe) | ||
| 323 | { | ||
| 324 | struct drm_crtc *crtc; | ||
| 325 | |||
| 326 | list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) { | ||
| 327 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 328 | |||
| 329 | if (dc->pipe == pipe) | ||
| 330 | return crtc; | ||
| 331 | } | ||
| 332 | |||
| 333 | return NULL; | ||
| 334 | } | ||
| 335 | |||
| 336 | static u32 tegra_drm_get_vblank_counter(struct drm_device *dev, int crtc) | ||
| 337 | { | ||
| 338 | /* TODO: implement real hardware counter using syncpoints */ | ||
| 339 | return drm_vblank_count(dev, crtc); | ||
| 340 | } | ||
| 341 | |||
| 342 | static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) | ||
| 343 | { | ||
| 344 | struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); | ||
| 345 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 346 | |||
| 347 | if (!crtc) | ||
| 348 | return -ENODEV; | ||
| 349 | |||
| 350 | tegra_dc_enable_vblank(dc); | ||
| 351 | |||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | |||
| 355 | static void tegra_drm_disable_vblank(struct drm_device *drm, int pipe) | ||
| 356 | { | ||
| 357 | struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); | ||
| 358 | struct tegra_dc *dc = to_tegra_dc(crtc); | ||
| 359 | |||
| 360 | if (crtc) | ||
| 361 | tegra_dc_disable_vblank(dc); | ||
| 362 | } | ||
| 363 | |||
| 364 | static void tegra_drm_preclose(struct drm_device *drm, struct drm_file *file) | ||
| 365 | { | ||
| 366 | struct tegra_drm_file *fpriv = file->driver_priv; | ||
| 367 | struct tegra_drm_context *context, *tmp; | ||
| 368 | struct drm_crtc *crtc; | ||
| 369 | |||
| 370 | list_for_each_entry(crtc, &drm->mode_config.crtc_list, head) | ||
| 371 | tegra_dc_cancel_page_flip(crtc, file); | ||
| 372 | |||
| 373 | list_for_each_entry_safe(context, tmp, &fpriv->contexts, list) | ||
| 374 | tegra_drm_context_free(context); | ||
| 375 | |||
| 376 | kfree(fpriv); | ||
| 377 | } | ||
| 378 | |||
| 379 | #ifdef CONFIG_DEBUG_FS | ||
| 380 | static int tegra_debugfs_framebuffers(struct seq_file *s, void *data) | ||
| 381 | { | ||
| 382 | struct drm_info_node *node = (struct drm_info_node *)s->private; | ||
| 383 | struct drm_device *drm = node->minor->dev; | ||
| 384 | struct drm_framebuffer *fb; | ||
| 385 | |||
| 386 | mutex_lock(&drm->mode_config.fb_lock); | ||
| 387 | |||
| 388 | list_for_each_entry(fb, &drm->mode_config.fb_list, head) { | ||
| 389 | seq_printf(s, "%3d: user size: %d x %d, depth %d, %d bpp, refcount %d\n", | ||
| 390 | fb->base.id, fb->width, fb->height, fb->depth, | ||
| 391 | fb->bits_per_pixel, | ||
| 392 | atomic_read(&fb->refcount.refcount)); | ||
| 393 | } | ||
| 394 | |||
| 395 | mutex_unlock(&drm->mode_config.fb_lock); | ||
| 396 | |||
| 397 | return 0; | ||
| 398 | } | ||
| 399 | |||
| 400 | static struct drm_info_list tegra_debugfs_list[] = { | ||
| 401 | { "framebuffers", tegra_debugfs_framebuffers, 0 }, | ||
| 402 | }; | ||
| 403 | |||
| 404 | static int tegra_debugfs_init(struct drm_minor *minor) | ||
| 405 | { | ||
| 406 | return drm_debugfs_create_files(tegra_debugfs_list, | ||
| 407 | ARRAY_SIZE(tegra_debugfs_list), | ||
| 408 | minor->debugfs_root, minor); | ||
| 409 | } | ||
| 410 | |||
| 411 | static void tegra_debugfs_cleanup(struct drm_minor *minor) | ||
| 412 | { | ||
| 413 | drm_debugfs_remove_files(tegra_debugfs_list, | ||
| 414 | ARRAY_SIZE(tegra_debugfs_list), minor); | ||
| 415 | } | ||
| 416 | #endif | ||
| 417 | |||
| 418 | struct drm_driver tegra_drm_driver = { | ||
| 419 | .driver_features = DRIVER_MODESET | DRIVER_GEM, | ||
| 420 | .load = tegra_drm_load, | ||
| 421 | .unload = tegra_drm_unload, | ||
| 422 | .open = tegra_drm_open, | ||
| 423 | .preclose = tegra_drm_preclose, | ||
| 424 | .lastclose = tegra_drm_lastclose, | ||
| 425 | |||
| 426 | .get_vblank_counter = tegra_drm_get_vblank_counter, | ||
| 427 | .enable_vblank = tegra_drm_enable_vblank, | ||
| 428 | .disable_vblank = tegra_drm_disable_vblank, | ||
| 429 | |||
| 430 | #if defined(CONFIG_DEBUG_FS) | ||
| 431 | .debugfs_init = tegra_debugfs_init, | ||
| 432 | .debugfs_cleanup = tegra_debugfs_cleanup, | ||
| 433 | #endif | ||
| 434 | |||
| 435 | .gem_free_object = tegra_bo_free_object, | ||
| 436 | .gem_vm_ops = &tegra_bo_vm_ops, | ||
| 437 | .dumb_create = tegra_bo_dumb_create, | ||
| 438 | .dumb_map_offset = tegra_bo_dumb_map_offset, | ||
| 439 | .dumb_destroy = drm_gem_dumb_destroy, | ||
| 440 | |||
| 441 | .ioctls = tegra_drm_ioctls, | ||
| 442 | .num_ioctls = ARRAY_SIZE(tegra_drm_ioctls), | ||
| 443 | .fops = &tegra_drm_fops, | ||
| 444 | |||
| 445 | .name = DRIVER_NAME, | ||
| 446 | .desc = DRIVER_DESC, | ||
| 447 | .date = DRIVER_DATE, | ||
| 448 | .major = DRIVER_MAJOR, | ||
| 449 | .minor = DRIVER_MINOR, | ||
| 450 | .patchlevel = DRIVER_PATCHLEVEL, | ||
| 451 | }; | ||
| 452 | |||
| 453 | int tegra_drm_register_client(struct tegra_drm *tegra, | ||
| 454 | struct tegra_drm_client *client) | ||
| 455 | { | ||
| 456 | mutex_lock(&tegra->clients_lock); | ||
| 457 | list_add_tail(&client->list, &tegra->clients); | ||
| 458 | mutex_unlock(&tegra->clients_lock); | ||
| 459 | |||
| 460 | return 0; | ||
| 461 | } | ||
| 462 | |||
| 463 | int tegra_drm_unregister_client(struct tegra_drm *tegra, | ||
| 464 | struct tegra_drm_client *client) | ||
| 465 | { | ||
| 466 | mutex_lock(&tegra->clients_lock); | ||
| 467 | list_del_init(&client->list); | ||
| 468 | mutex_unlock(&tegra->clients_lock); | ||
| 469 | |||
| 470 | return 0; | ||
| 471 | } | ||
| 472 | |||
| 473 | static int host1x_drm_probe(struct host1x_device *device) | ||
| 474 | { | ||
| 475 | return drm_host1x_init(&tegra_drm_driver, device); | ||
| 476 | } | ||
| 477 | |||
| 478 | static int host1x_drm_remove(struct host1x_device *device) | ||
| 479 | { | ||
| 480 | drm_host1x_exit(&tegra_drm_driver, device); | ||
| 481 | |||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | static const struct of_device_id host1x_drm_subdevs[] = { | ||
| 486 | { .compatible = "nvidia,tegra20-dc", }, | ||
| 487 | { .compatible = "nvidia,tegra20-hdmi", }, | ||
| 488 | { .compatible = "nvidia,tegra20-gr2d", }, | ||
| 489 | { .compatible = "nvidia,tegra30-dc", }, | ||
| 490 | { .compatible = "nvidia,tegra30-hdmi", }, | ||
| 491 | { .compatible = "nvidia,tegra30-gr2d", }, | ||
| 492 | { /* sentinel */ } | ||
| 493 | }; | ||
| 494 | |||
| 495 | static struct host1x_driver host1x_drm_driver = { | ||
| 496 | .name = "drm", | ||
| 497 | .probe = host1x_drm_probe, | ||
| 498 | .remove = host1x_drm_remove, | ||
| 499 | .subdevs = host1x_drm_subdevs, | ||
| 500 | }; | ||
| 501 | |||
| 502 | static int __init host1x_drm_init(void) | ||
| 503 | { | ||
| 504 | int err; | ||
| 505 | |||
| 506 | err = host1x_driver_register(&host1x_drm_driver); | ||
| 507 | if (err < 0) | ||
| 508 | return err; | ||
| 509 | |||
| 510 | err = platform_driver_register(&tegra_dc_driver); | ||
| 511 | if (err < 0) | ||
| 512 | goto unregister_host1x; | ||
| 513 | |||
| 514 | err = platform_driver_register(&tegra_hdmi_driver); | ||
| 515 | if (err < 0) | ||
| 516 | goto unregister_dc; | ||
| 517 | |||
| 518 | err = platform_driver_register(&tegra_gr2d_driver); | ||
| 519 | if (err < 0) | ||
| 520 | goto unregister_hdmi; | ||
| 521 | |||
| 522 | return 0; | ||
| 523 | |||
| 524 | unregister_hdmi: | ||
| 525 | platform_driver_unregister(&tegra_hdmi_driver); | ||
| 526 | unregister_dc: | ||
| 527 | platform_driver_unregister(&tegra_dc_driver); | ||
| 528 | unregister_host1x: | ||
| 529 | host1x_driver_unregister(&host1x_drm_driver); | ||
| 530 | return err; | ||
| 531 | } | ||
| 532 | module_init(host1x_drm_init); | ||
| 533 | |||
| 534 | static void __exit host1x_drm_exit(void) | ||
| 535 | { | ||
| 536 | platform_driver_unregister(&tegra_gr2d_driver); | ||
| 537 | platform_driver_unregister(&tegra_hdmi_driver); | ||
| 538 | platform_driver_unregister(&tegra_dc_driver); | ||
| 539 | host1x_driver_unregister(&host1x_drm_driver); | ||
| 540 | } | ||
| 541 | module_exit(host1x_drm_exit); | ||
| 542 | |||
| 543 | MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); | ||
| 544 | MODULE_DESCRIPTION("NVIDIA Tegra DRM driver"); | ||
| 545 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/gpu/host1x/drm/drm.h b/drivers/gpu/host1x/drm/drm.h deleted file mode 100644 index 25522e23c7b8..000000000000 --- a/drivers/gpu/host1x/drm/drm.h +++ /dev/null | |||
| @@ -1,258 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012-2013 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef HOST1X_DRM_H | ||
| 11 | #define HOST1X_DRM_H 1 | ||
| 12 | |||
| 13 | #include <uapi/drm/tegra_drm.h> | ||
| 14 | #include <linux/host1x.h> | ||
| 15 | |||
| 16 | #include <drm/drmP.h> | ||
| 17 | #include <drm/drm_crtc_helper.h> | ||
| 18 | #include <drm/drm_edid.h> | ||
| 19 | #include <drm/drm_fb_helper.h> | ||
| 20 | #include <drm/drm_fixed.h> | ||
| 21 | |||
| 22 | struct tegra_fb { | ||
| 23 | struct drm_framebuffer base; | ||
| 24 | struct tegra_bo **planes; | ||
| 25 | unsigned int num_planes; | ||
| 26 | }; | ||
| 27 | |||
| 28 | struct tegra_fbdev { | ||
| 29 | struct drm_fb_helper base; | ||
| 30 | struct tegra_fb *fb; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct tegra_drm { | ||
| 34 | struct drm_device *drm; | ||
| 35 | |||
| 36 | struct mutex clients_lock; | ||
| 37 | struct list_head clients; | ||
| 38 | |||
| 39 | struct tegra_fbdev *fbdev; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct tegra_drm_client; | ||
| 43 | |||
| 44 | struct tegra_drm_context { | ||
| 45 | struct tegra_drm_client *client; | ||
| 46 | struct host1x_channel *channel; | ||
| 47 | struct list_head list; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct tegra_drm_client_ops { | ||
| 51 | int (*open_channel)(struct tegra_drm_client *client, | ||
| 52 | struct tegra_drm_context *context); | ||
| 53 | void (*close_channel)(struct tegra_drm_context *context); | ||
| 54 | int (*submit)(struct tegra_drm_context *context, | ||
| 55 | struct drm_tegra_submit *args, struct drm_device *drm, | ||
| 56 | struct drm_file *file); | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct tegra_drm_client { | ||
| 60 | struct host1x_client base; | ||
| 61 | struct list_head list; | ||
| 62 | |||
| 63 | const struct tegra_drm_client_ops *ops; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static inline struct tegra_drm_client * | ||
| 67 | host1x_to_drm_client(struct host1x_client *client) | ||
| 68 | { | ||
| 69 | return container_of(client, struct tegra_drm_client, base); | ||
| 70 | } | ||
| 71 | |||
| 72 | extern int tegra_drm_register_client(struct tegra_drm *tegra, | ||
| 73 | struct tegra_drm_client *client); | ||
| 74 | extern int tegra_drm_unregister_client(struct tegra_drm *tegra, | ||
| 75 | struct tegra_drm_client *client); | ||
| 76 | |||
| 77 | extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm); | ||
| 78 | extern int tegra_drm_exit(struct tegra_drm *tegra); | ||
| 79 | |||
| 80 | struct tegra_output; | ||
| 81 | |||
| 82 | struct tegra_dc { | ||
| 83 | struct host1x_client client; | ||
| 84 | struct device *dev; | ||
| 85 | spinlock_t lock; | ||
| 86 | |||
| 87 | struct drm_crtc base; | ||
| 88 | int pipe; | ||
| 89 | |||
| 90 | struct clk *clk; | ||
| 91 | void __iomem *regs; | ||
| 92 | int irq; | ||
| 93 | |||
| 94 | struct tegra_output *rgb; | ||
| 95 | |||
| 96 | struct list_head list; | ||
| 97 | |||
| 98 | struct drm_info_list *debugfs_files; | ||
| 99 | struct drm_minor *minor; | ||
| 100 | struct dentry *debugfs; | ||
| 101 | |||
| 102 | /* page-flip handling */ | ||
| 103 | struct drm_pending_vblank_event *event; | ||
| 104 | }; | ||
| 105 | |||
| 106 | static inline struct tegra_dc * | ||
| 107 | host1x_client_to_dc(struct host1x_client *client) | ||
| 108 | { | ||
| 109 | return container_of(client, struct tegra_dc, client); | ||
| 110 | } | ||
| 111 | |||
| 112 | static inline struct tegra_dc *to_tegra_dc(struct drm_crtc *crtc) | ||
| 113 | { | ||
| 114 | return container_of(crtc, struct tegra_dc, base); | ||
| 115 | } | ||
| 116 | |||
| 117 | static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long value, | ||
| 118 | unsigned long reg) | ||
| 119 | { | ||
| 120 | writel(value, dc->regs + (reg << 2)); | ||
| 121 | } | ||
| 122 | |||
| 123 | static inline unsigned long tegra_dc_readl(struct tegra_dc *dc, | ||
| 124 | unsigned long reg) | ||
| 125 | { | ||
| 126 | return readl(dc->regs + (reg << 2)); | ||
| 127 | } | ||
| 128 | |||
| 129 | struct tegra_dc_window { | ||
| 130 | struct { | ||
| 131 | unsigned int x; | ||
| 132 | unsigned int y; | ||
| 133 | unsigned int w; | ||
| 134 | unsigned int h; | ||
| 135 | } src; | ||
| 136 | struct { | ||
| 137 | unsigned int x; | ||
| 138 | unsigned int y; | ||
| 139 | unsigned int w; | ||
| 140 | unsigned int h; | ||
| 141 | } dst; | ||
| 142 | unsigned int bits_per_pixel; | ||
| 143 | unsigned int format; | ||
| 144 | unsigned int stride[2]; | ||
| 145 | unsigned long base[3]; | ||
| 146 | }; | ||
| 147 | |||
| 148 | /* from dc.c */ | ||
| 149 | extern unsigned int tegra_dc_format(uint32_t format); | ||
| 150 | extern int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index, | ||
| 151 | const struct tegra_dc_window *window); | ||
| 152 | extern void tegra_dc_enable_vblank(struct tegra_dc *dc); | ||
| 153 | extern void tegra_dc_disable_vblank(struct tegra_dc *dc); | ||
| 154 | extern void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, | ||
| 155 | struct drm_file *file); | ||
| 156 | |||
| 157 | struct tegra_output_ops { | ||
| 158 | int (*enable)(struct tegra_output *output); | ||
| 159 | int (*disable)(struct tegra_output *output); | ||
| 160 | int (*setup_clock)(struct tegra_output *output, struct clk *clk, | ||
| 161 | unsigned long pclk); | ||
| 162 | int (*check_mode)(struct tegra_output *output, | ||
| 163 | struct drm_display_mode *mode, | ||
| 164 | enum drm_mode_status *status); | ||
| 165 | }; | ||
| 166 | |||
| 167 | enum tegra_output_type { | ||
| 168 | TEGRA_OUTPUT_RGB, | ||
| 169 | TEGRA_OUTPUT_HDMI, | ||
| 170 | }; | ||
| 171 | |||
| 172 | struct tegra_output { | ||
| 173 | struct device_node *of_node; | ||
| 174 | struct device *dev; | ||
| 175 | |||
| 176 | const struct tegra_output_ops *ops; | ||
| 177 | enum tegra_output_type type; | ||
| 178 | |||
| 179 | struct i2c_adapter *ddc; | ||
| 180 | const struct edid *edid; | ||
| 181 | unsigned int hpd_irq; | ||
| 182 | int hpd_gpio; | ||
| 183 | |||
| 184 | struct drm_encoder encoder; | ||
| 185 | struct drm_connector connector; | ||
| 186 | }; | ||
| 187 | |||
| 188 | static inline struct tegra_output *encoder_to_output(struct drm_encoder *e) | ||
| 189 | { | ||
| 190 | return container_of(e, struct tegra_output, encoder); | ||
| 191 | } | ||
| 192 | |||
| 193 | static inline struct tegra_output *connector_to_output(struct drm_connector *c) | ||
| 194 | { | ||
| 195 | return container_of(c, struct tegra_output, connector); | ||
| 196 | } | ||
| 197 | |||
| 198 | static inline int tegra_output_enable(struct tegra_output *output) | ||
| 199 | { | ||
| 200 | if (output && output->ops && output->ops->enable) | ||
| 201 | return output->ops->enable(output); | ||
| 202 | |||
| 203 | return output ? -ENOSYS : -EINVAL; | ||
| 204 | } | ||
| 205 | |||
| 206 | static inline int tegra_output_disable(struct tegra_output *output) | ||
| 207 | { | ||
| 208 | if (output && output->ops && output->ops->disable) | ||
| 209 | return output->ops->disable(output); | ||
| 210 | |||
| 211 | return output ? -ENOSYS : -EINVAL; | ||
| 212 | } | ||
| 213 | |||
| 214 | static inline int tegra_output_setup_clock(struct tegra_output *output, | ||
| 215 | struct clk *clk, unsigned long pclk) | ||
| 216 | { | ||
| 217 | if (output && output->ops && output->ops->setup_clock) | ||
| 218 | return output->ops->setup_clock(output, clk, pclk); | ||
| 219 | |||
| 220 | return output ? -ENOSYS : -EINVAL; | ||
| 221 | } | ||
| 222 | |||
| 223 | static inline int tegra_output_check_mode(struct tegra_output *output, | ||
| 224 | struct drm_display_mode *mode, | ||
| 225 | enum drm_mode_status *status) | ||
| 226 | { | ||
| 227 | if (output && output->ops && output->ops->check_mode) | ||
| 228 | return output->ops->check_mode(output, mode, status); | ||
| 229 | |||
| 230 | return output ? -ENOSYS : -EINVAL; | ||
| 231 | } | ||
| 232 | |||
| 233 | /* from bus.c */ | ||
| 234 | int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device); | ||
| 235 | void drm_host1x_exit(struct drm_driver *driver, struct host1x_device *device); | ||
| 236 | |||
| 237 | /* from rgb.c */ | ||
| 238 | extern int tegra_dc_rgb_probe(struct tegra_dc *dc); | ||
| 239 | extern int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc); | ||
| 240 | extern int tegra_dc_rgb_exit(struct tegra_dc *dc); | ||
| 241 | |||
| 242 | /* from output.c */ | ||
| 243 | extern int tegra_output_parse_dt(struct tegra_output *output); | ||
| 244 | extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output); | ||
| 245 | extern int tegra_output_exit(struct tegra_output *output); | ||
| 246 | |||
| 247 | /* from fb.c */ | ||
| 248 | struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, | ||
| 249 | unsigned int index); | ||
| 250 | extern int tegra_drm_fb_init(struct drm_device *drm); | ||
| 251 | extern void tegra_drm_fb_exit(struct drm_device *drm); | ||
| 252 | extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev); | ||
| 253 | |||
| 254 | extern struct platform_driver tegra_dc_driver; | ||
| 255 | extern struct platform_driver tegra_hdmi_driver; | ||
| 256 | extern struct platform_driver tegra_gr2d_driver; | ||
| 257 | |||
| 258 | #endif /* HOST1X_DRM_H */ | ||
diff --git a/drivers/gpu/host1x/drm/fb.c b/drivers/gpu/host1x/drm/fb.c deleted file mode 100644 index 1fd4e196b934..000000000000 --- a/drivers/gpu/host1x/drm/fb.c +++ /dev/null | |||
| @@ -1,372 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012-2013 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * Based on the KMS/FB CMA helpers | ||
| 6 | * Copyright (C) 2012 Analog Device Inc. | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License version 2 as | ||
| 10 | * published by the Free Software Foundation. | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include "drm.h" | ||
| 14 | #include "gem.h" | ||
| 15 | |||
| 16 | static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb) | ||
| 17 | { | ||
| 18 | return container_of(fb, struct tegra_fb, base); | ||
| 19 | } | ||
| 20 | |||
| 21 | static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper) | ||
| 22 | { | ||
| 23 | return container_of(helper, struct tegra_fbdev, base); | ||
| 24 | } | ||
| 25 | |||
| 26 | struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer, | ||
| 27 | unsigned int index) | ||
| 28 | { | ||
| 29 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | ||
| 30 | |||
| 31 | if (index >= drm_format_num_planes(framebuffer->pixel_format)) | ||
| 32 | return NULL; | ||
| 33 | |||
| 34 | return fb->planes[index]; | ||
| 35 | } | ||
| 36 | |||
| 37 | static void tegra_fb_destroy(struct drm_framebuffer *framebuffer) | ||
| 38 | { | ||
| 39 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | ||
| 40 | unsigned int i; | ||
| 41 | |||
| 42 | for (i = 0; i < fb->num_planes; i++) { | ||
| 43 | struct tegra_bo *bo = fb->planes[i]; | ||
| 44 | |||
| 45 | if (bo) | ||
| 46 | drm_gem_object_unreference_unlocked(&bo->gem); | ||
| 47 | } | ||
| 48 | |||
| 49 | drm_framebuffer_cleanup(framebuffer); | ||
| 50 | kfree(fb->planes); | ||
| 51 | kfree(fb); | ||
| 52 | } | ||
| 53 | |||
| 54 | static int tegra_fb_create_handle(struct drm_framebuffer *framebuffer, | ||
| 55 | struct drm_file *file, unsigned int *handle) | ||
| 56 | { | ||
| 57 | struct tegra_fb *fb = to_tegra_fb(framebuffer); | ||
| 58 | |||
| 59 | return drm_gem_handle_create(file, &fb->planes[0]->gem, handle); | ||
| 60 | } | ||
| 61 | |||
| 62 | static struct drm_framebuffer_funcs tegra_fb_funcs = { | ||
| 63 | .destroy = tegra_fb_destroy, | ||
| 64 | .create_handle = tegra_fb_create_handle, | ||
| 65 | }; | ||
| 66 | |||
| 67 | static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm, | ||
| 68 | struct drm_mode_fb_cmd2 *mode_cmd, | ||
| 69 | struct tegra_bo **planes, | ||
| 70 | unsigned int num_planes) | ||
| 71 | { | ||
| 72 | struct tegra_fb *fb; | ||
| 73 | unsigned int i; | ||
| 74 | int err; | ||
| 75 | |||
| 76 | fb = kzalloc(sizeof(*fb), GFP_KERNEL); | ||
| 77 | if (!fb) | ||
| 78 | return ERR_PTR(-ENOMEM); | ||
| 79 | |||
| 80 | fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL); | ||
| 81 | if (!fb->planes) | ||
| 82 | return ERR_PTR(-ENOMEM); | ||
| 83 | |||
| 84 | fb->num_planes = num_planes; | ||
| 85 | |||
| 86 | drm_helper_mode_fill_fb_struct(&fb->base, mode_cmd); | ||
| 87 | |||
| 88 | for (i = 0; i < fb->num_planes; i++) | ||
| 89 | fb->planes[i] = planes[i]; | ||
| 90 | |||
| 91 | err = drm_framebuffer_init(drm, &fb->base, &tegra_fb_funcs); | ||
| 92 | if (err < 0) { | ||
| 93 | dev_err(drm->dev, "failed to initialize framebuffer: %d\n", | ||
| 94 | err); | ||
| 95 | kfree(fb->planes); | ||
| 96 | kfree(fb); | ||
| 97 | return ERR_PTR(err); | ||
| 98 | } | ||
| 99 | |||
| 100 | return fb; | ||
| 101 | } | ||
| 102 | |||
| 103 | static struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, | ||
| 104 | struct drm_file *file, | ||
| 105 | struct drm_mode_fb_cmd2 *cmd) | ||
| 106 | { | ||
| 107 | unsigned int hsub, vsub, i; | ||
| 108 | struct tegra_bo *planes[4]; | ||
| 109 | struct drm_gem_object *gem; | ||
| 110 | struct tegra_fb *fb; | ||
| 111 | int err; | ||
| 112 | |||
| 113 | hsub = drm_format_horz_chroma_subsampling(cmd->pixel_format); | ||
| 114 | vsub = drm_format_vert_chroma_subsampling(cmd->pixel_format); | ||
| 115 | |||
| 116 | for (i = 0; i < drm_format_num_planes(cmd->pixel_format); i++) { | ||
| 117 | unsigned int width = cmd->width / (i ? hsub : 1); | ||
| 118 | unsigned int height = cmd->height / (i ? vsub : 1); | ||
| 119 | unsigned int size, bpp; | ||
| 120 | |||
| 121 | gem = drm_gem_object_lookup(drm, file, cmd->handles[i]); | ||
| 122 | if (!gem) { | ||
| 123 | err = -ENXIO; | ||
| 124 | goto unreference; | ||
| 125 | } | ||
| 126 | |||
| 127 | bpp = drm_format_plane_cpp(cmd->pixel_format, i); | ||
| 128 | |||
| 129 | size = (height - 1) * cmd->pitches[i] + | ||
| 130 | width * bpp + cmd->offsets[i]; | ||
| 131 | |||
| 132 | if (gem->size < size) { | ||
| 133 | err = -EINVAL; | ||
| 134 | goto unreference; | ||
| 135 | } | ||
| 136 | |||
| 137 | planes[i] = to_tegra_bo(gem); | ||
| 138 | } | ||
| 139 | |||
| 140 | fb = tegra_fb_alloc(drm, cmd, planes, i); | ||
| 141 | if (IS_ERR(fb)) { | ||
| 142 | err = PTR_ERR(fb); | ||
| 143 | goto unreference; | ||
| 144 | } | ||
| 145 | |||
| 146 | return &fb->base; | ||
| 147 | |||
| 148 | unreference: | ||
| 149 | while (i--) | ||
| 150 | drm_gem_object_unreference_unlocked(&planes[i]->gem); | ||
| 151 | |||
| 152 | return ERR_PTR(err); | ||
| 153 | } | ||
| 154 | |||
| 155 | static struct fb_ops tegra_fb_ops = { | ||
| 156 | .owner = THIS_MODULE, | ||
| 157 | .fb_fillrect = sys_fillrect, | ||
| 158 | .fb_copyarea = sys_copyarea, | ||
| 159 | .fb_imageblit = sys_imageblit, | ||
| 160 | .fb_check_var = drm_fb_helper_check_var, | ||
| 161 | .fb_set_par = drm_fb_helper_set_par, | ||
| 162 | .fb_blank = drm_fb_helper_blank, | ||
| 163 | .fb_pan_display = drm_fb_helper_pan_display, | ||
| 164 | .fb_setcmap = drm_fb_helper_setcmap, | ||
| 165 | }; | ||
| 166 | |||
| 167 | static int tegra_fbdev_probe(struct drm_fb_helper *helper, | ||
| 168 | struct drm_fb_helper_surface_size *sizes) | ||
| 169 | { | ||
| 170 | struct tegra_fbdev *fbdev = to_tegra_fbdev(helper); | ||
| 171 | struct drm_device *drm = helper->dev; | ||
| 172 | struct drm_mode_fb_cmd2 cmd = { 0 }; | ||
| 173 | unsigned int bytes_per_pixel; | ||
| 174 | struct drm_framebuffer *fb; | ||
| 175 | unsigned long offset; | ||
| 176 | struct fb_info *info; | ||
| 177 | struct tegra_bo *bo; | ||
| 178 | size_t size; | ||
| 179 | int err; | ||
| 180 | |||
| 181 | bytes_per_pixel = DIV_ROUND_UP(sizes->surface_bpp, 8); | ||
| 182 | |||
| 183 | cmd.width = sizes->surface_width; | ||
| 184 | cmd.height = sizes->surface_height; | ||
| 185 | cmd.pitches[0] = sizes->surface_width * bytes_per_pixel; | ||
| 186 | cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp, | ||
| 187 | sizes->surface_depth); | ||
| 188 | |||
| 189 | size = cmd.pitches[0] * cmd.height; | ||
| 190 | |||
| 191 | bo = tegra_bo_create(drm, size); | ||
| 192 | if (IS_ERR(bo)) | ||
| 193 | return PTR_ERR(bo); | ||
| 194 | |||
| 195 | info = framebuffer_alloc(0, drm->dev); | ||
| 196 | if (!info) { | ||
| 197 | dev_err(drm->dev, "failed to allocate framebuffer info\n"); | ||
| 198 | tegra_bo_free_object(&bo->gem); | ||
| 199 | return -ENOMEM; | ||
| 200 | } | ||
| 201 | |||
| 202 | fbdev->fb = tegra_fb_alloc(drm, &cmd, &bo, 1); | ||
| 203 | if (IS_ERR(fbdev->fb)) { | ||
| 204 | dev_err(drm->dev, "failed to allocate DRM framebuffer\n"); | ||
| 205 | err = PTR_ERR(fbdev->fb); | ||
| 206 | goto release; | ||
| 207 | } | ||
| 208 | |||
| 209 | fb = &fbdev->fb->base; | ||
| 210 | helper->fb = fb; | ||
| 211 | helper->fbdev = info; | ||
| 212 | |||
| 213 | info->par = helper; | ||
| 214 | info->flags = FBINFO_FLAG_DEFAULT; | ||
| 215 | info->fbops = &tegra_fb_ops; | ||
| 216 | |||
| 217 | err = fb_alloc_cmap(&info->cmap, 256, 0); | ||
| 218 | if (err < 0) { | ||
| 219 | dev_err(drm->dev, "failed to allocate color map: %d\n", err); | ||
| 220 | goto destroy; | ||
| 221 | } | ||
| 222 | |||
| 223 | drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth); | ||
| 224 | drm_fb_helper_fill_var(info, helper, fb->width, fb->height); | ||
| 225 | |||
| 226 | offset = info->var.xoffset * bytes_per_pixel + | ||
| 227 | info->var.yoffset * fb->pitches[0]; | ||
| 228 | |||
| 229 | drm->mode_config.fb_base = (resource_size_t)bo->paddr; | ||
| 230 | info->screen_base = bo->vaddr + offset; | ||
| 231 | info->screen_size = size; | ||
| 232 | info->fix.smem_start = (unsigned long)(bo->paddr + offset); | ||
| 233 | info->fix.smem_len = size; | ||
| 234 | |||
| 235 | return 0; | ||
| 236 | |||
| 237 | destroy: | ||
| 238 | drm_framebuffer_unregister_private(fb); | ||
| 239 | tegra_fb_destroy(fb); | ||
| 240 | release: | ||
| 241 | framebuffer_release(info); | ||
| 242 | return err; | ||
| 243 | } | ||
| 244 | |||
| 245 | static struct drm_fb_helper_funcs tegra_fb_helper_funcs = { | ||
| 246 | .fb_probe = tegra_fbdev_probe, | ||
| 247 | }; | ||
| 248 | |||
| 249 | static struct tegra_fbdev *tegra_fbdev_create(struct drm_device *drm, | ||
| 250 | unsigned int preferred_bpp, | ||
| 251 | unsigned int num_crtc, | ||
| 252 | unsigned int max_connectors) | ||
| 253 | { | ||
| 254 | struct drm_fb_helper *helper; | ||
| 255 | struct tegra_fbdev *fbdev; | ||
| 256 | int err; | ||
| 257 | |||
| 258 | fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL); | ||
| 259 | if (!fbdev) { | ||
| 260 | dev_err(drm->dev, "failed to allocate DRM fbdev\n"); | ||
| 261 | return ERR_PTR(-ENOMEM); | ||
| 262 | } | ||
| 263 | |||
| 264 | fbdev->base.funcs = &tegra_fb_helper_funcs; | ||
| 265 | helper = &fbdev->base; | ||
| 266 | |||
| 267 | err = drm_fb_helper_init(drm, &fbdev->base, num_crtc, max_connectors); | ||
| 268 | if (err < 0) { | ||
| 269 | dev_err(drm->dev, "failed to initialize DRM FB helper\n"); | ||
| 270 | goto free; | ||
| 271 | } | ||
| 272 | |||
| 273 | err = drm_fb_helper_single_add_all_connectors(&fbdev->base); | ||
| 274 | if (err < 0) { | ||
| 275 | dev_err(drm->dev, "failed to add connectors\n"); | ||
| 276 | goto fini; | ||
| 277 | } | ||
| 278 | |||
| 279 | drm_helper_disable_unused_functions(drm); | ||
| 280 | |||
| 281 | err = drm_fb_helper_initial_config(&fbdev->base, preferred_bpp); | ||
| 282 | if (err < 0) { | ||
| 283 | dev_err(drm->dev, "failed to set initial configuration\n"); | ||
| 284 | goto fini; | ||
| 285 | } | ||
| 286 | |||
| 287 | return fbdev; | ||
| 288 | |||
| 289 | fini: | ||
| 290 | drm_fb_helper_fini(&fbdev->base); | ||
| 291 | free: | ||
| 292 | kfree(fbdev); | ||
| 293 | return ERR_PTR(err); | ||
| 294 | } | ||
| 295 | |||
| 296 | static void tegra_fbdev_free(struct tegra_fbdev *fbdev) | ||
| 297 | { | ||
| 298 | struct fb_info *info = fbdev->base.fbdev; | ||
| 299 | |||
| 300 | if (info) { | ||
| 301 | int err; | ||
| 302 | |||
| 303 | err = unregister_framebuffer(info); | ||
| 304 | if (err < 0) | ||
| 305 | DRM_DEBUG_KMS("failed to unregister framebuffer\n"); | ||
| 306 | |||
| 307 | if (info->cmap.len) | ||
| 308 | fb_dealloc_cmap(&info->cmap); | ||
| 309 | |||
| 310 | framebuffer_release(info); | ||
| 311 | } | ||
| 312 | |||
| 313 | if (fbdev->fb) { | ||
| 314 | drm_framebuffer_unregister_private(&fbdev->fb->base); | ||
| 315 | tegra_fb_destroy(&fbdev->fb->base); | ||
| 316 | } | ||
| 317 | |||
| 318 | drm_fb_helper_fini(&fbdev->base); | ||
| 319 | kfree(fbdev); | ||
| 320 | } | ||
| 321 | |||
| 322 | static void tegra_fb_output_poll_changed(struct drm_device *drm) | ||
| 323 | { | ||
| 324 | struct tegra_drm *tegra = drm->dev_private; | ||
| 325 | |||
| 326 | if (tegra->fbdev) | ||
| 327 | drm_fb_helper_hotplug_event(&tegra->fbdev->base); | ||
| 328 | } | ||
| 329 | |||
| 330 | static const struct drm_mode_config_funcs tegra_drm_mode_funcs = { | ||
| 331 | .fb_create = tegra_fb_create, | ||
| 332 | .output_poll_changed = tegra_fb_output_poll_changed, | ||
| 333 | }; | ||
| 334 | |||
| 335 | int tegra_drm_fb_init(struct drm_device *drm) | ||
| 336 | { | ||
| 337 | struct tegra_drm *tegra = drm->dev_private; | ||
| 338 | struct tegra_fbdev *fbdev; | ||
| 339 | |||
| 340 | drm->mode_config.min_width = 0; | ||
| 341 | drm->mode_config.min_height = 0; | ||
| 342 | |||
| 343 | drm->mode_config.max_width = 4096; | ||
| 344 | drm->mode_config.max_height = 4096; | ||
| 345 | |||
| 346 | drm->mode_config.funcs = &tegra_drm_mode_funcs; | ||
| 347 | |||
| 348 | fbdev = tegra_fbdev_create(drm, 32, drm->mode_config.num_crtc, | ||
| 349 | drm->mode_config.num_connector); | ||
| 350 | if (IS_ERR(fbdev)) | ||
| 351 | return PTR_ERR(fbdev); | ||
| 352 | |||
| 353 | tegra->fbdev = fbdev; | ||
| 354 | |||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | void tegra_drm_fb_exit(struct drm_device *drm) | ||
| 359 | { | ||
| 360 | struct tegra_drm *tegra = drm->dev_private; | ||
| 361 | |||
| 362 | tegra_fbdev_free(tegra->fbdev); | ||
| 363 | } | ||
| 364 | |||
| 365 | void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev) | ||
| 366 | { | ||
| 367 | if (fbdev) { | ||
| 368 | drm_modeset_lock_all(fbdev->base.dev); | ||
| 369 | drm_fb_helper_restore_fbdev_mode(&fbdev->base); | ||
| 370 | drm_modeset_unlock_all(fbdev->base.dev); | ||
| 371 | } | ||
| 372 | } | ||
diff --git a/drivers/gpu/host1x/drm/gem.c b/drivers/gpu/host1x/drm/gem.c deleted file mode 100644 index 267c0c21e5cc..000000000000 --- a/drivers/gpu/host1x/drm/gem.c +++ /dev/null | |||
| @@ -1,248 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * NVIDIA Tegra DRM GEM helper functions | ||
| 3 | * | ||
| 4 | * Copyright (C) 2012 Sascha Hauer, Pengutronix | ||
| 5 | * Copyright (C) 2013 NVIDIA CORPORATION, All rights reserved. | ||
| 6 | * | ||
| 7 | * Based on the GEM/CMA helpers | ||
| 8 | * | ||
| 9 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU General Public License | ||
| 13 | * as published by the Free Software Foundation; either version 2 | ||
| 14 | * of the License, or (at your option) any later version. | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #include "gem.h" | ||
| 22 | |||
| 23 | static inline struct tegra_bo *host1x_to_tegra_bo(struct host1x_bo *bo) | ||
| 24 | { | ||
| 25 | return container_of(bo, struct tegra_bo, base); | ||
| 26 | } | ||
| 27 | |||
| 28 | static void tegra_bo_put(struct host1x_bo *bo) | ||
| 29 | { | ||
| 30 | struct tegra_bo *obj = host1x_to_tegra_bo(bo); | ||
| 31 | struct drm_device *drm = obj->gem.dev; | ||
| 32 | |||
| 33 | mutex_lock(&drm->struct_mutex); | ||
| 34 | drm_gem_object_unreference(&obj->gem); | ||
| 35 | mutex_unlock(&drm->struct_mutex); | ||
| 36 | } | ||
| 37 | |||
| 38 | static dma_addr_t tegra_bo_pin(struct host1x_bo *bo, struct sg_table **sgt) | ||
| 39 | { | ||
| 40 | struct tegra_bo *obj = host1x_to_tegra_bo(bo); | ||
| 41 | |||
| 42 | return obj->paddr; | ||
| 43 | } | ||
| 44 | |||
| 45 | static void tegra_bo_unpin(struct host1x_bo *bo, struct sg_table *sgt) | ||
| 46 | { | ||
| 47 | } | ||
| 48 | |||
| 49 | static void *tegra_bo_mmap(struct host1x_bo *bo) | ||
| 50 | { | ||
| 51 | struct tegra_bo *obj = host1x_to_tegra_bo(bo); | ||
| 52 | |||
| 53 | return obj->vaddr; | ||
| 54 | } | ||
| 55 | |||
| 56 | static void tegra_bo_munmap(struct host1x_bo *bo, void *addr) | ||
| 57 | { | ||
| 58 | } | ||
| 59 | |||
| 60 | static void *tegra_bo_kmap(struct host1x_bo *bo, unsigned int page) | ||
| 61 | { | ||
| 62 | struct tegra_bo *obj = host1x_to_tegra_bo(bo); | ||
| 63 | |||
| 64 | return obj->vaddr + page * PAGE_SIZE; | ||
| 65 | } | ||
| 66 | |||
| 67 | static void tegra_bo_kunmap(struct host1x_bo *bo, unsigned int page, | ||
| 68 | void *addr) | ||
| 69 | { | ||
| 70 | } | ||
| 71 | |||
| 72 | static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo) | ||
| 73 | { | ||
| 74 | struct tegra_bo *obj = host1x_to_tegra_bo(bo); | ||
| 75 | struct drm_device *drm = obj->gem.dev; | ||
| 76 | |||
| 77 | mutex_lock(&drm->struct_mutex); | ||
| 78 | drm_gem_object_reference(&obj->gem); | ||
| 79 | mutex_unlock(&drm->struct_mutex); | ||
| 80 | |||
| 81 | return bo; | ||
| 82 | } | ||
| 83 | |||
| 84 | const struct host1x_bo_ops tegra_bo_ops = { | ||
| 85 | .get = tegra_bo_get, | ||
| 86 | .put = tegra_bo_put, | ||
| 87 | .pin = tegra_bo_pin, | ||
| 88 | .unpin = tegra_bo_unpin, | ||
| 89 | .mmap = tegra_bo_mmap, | ||
| 90 | .munmap = tegra_bo_munmap, | ||
| 91 | .kmap = tegra_bo_kmap, | ||
| 92 | .kunmap = tegra_bo_kunmap, | ||
| 93 | }; | ||
| 94 | |||
| 95 | static void tegra_bo_destroy(struct drm_device *drm, struct tegra_bo *bo) | ||
| 96 | { | ||
| 97 | dma_free_writecombine(drm->dev, bo->gem.size, bo->vaddr, bo->paddr); | ||
| 98 | } | ||
| 99 | |||
| 100 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size) | ||
| 101 | { | ||
| 102 | struct tegra_bo *bo; | ||
| 103 | int err; | ||
| 104 | |||
| 105 | bo = kzalloc(sizeof(*bo), GFP_KERNEL); | ||
| 106 | if (!bo) | ||
| 107 | return ERR_PTR(-ENOMEM); | ||
| 108 | |||
| 109 | host1x_bo_init(&bo->base, &tegra_bo_ops); | ||
| 110 | size = round_up(size, PAGE_SIZE); | ||
| 111 | |||
| 112 | bo->vaddr = dma_alloc_writecombine(drm->dev, size, &bo->paddr, | ||
| 113 | GFP_KERNEL | __GFP_NOWARN); | ||
| 114 | if (!bo->vaddr) { | ||
| 115 | dev_err(drm->dev, "failed to allocate buffer with size %u\n", | ||
| 116 | size); | ||
| 117 | err = -ENOMEM; | ||
| 118 | goto err_dma; | ||
| 119 | } | ||
| 120 | |||
| 121 | err = drm_gem_object_init(drm, &bo->gem, size); | ||
| 122 | if (err) | ||
| 123 | goto err_init; | ||
| 124 | |||
| 125 | err = drm_gem_create_mmap_offset(&bo->gem); | ||
| 126 | if (err) | ||
| 127 | goto err_mmap; | ||
| 128 | |||
| 129 | return bo; | ||
| 130 | |||
| 131 | err_mmap: | ||
| 132 | drm_gem_object_release(&bo->gem); | ||
| 133 | err_init: | ||
| 134 | tegra_bo_destroy(drm, bo); | ||
| 135 | err_dma: | ||
| 136 | kfree(bo); | ||
| 137 | |||
| 138 | return ERR_PTR(err); | ||
| 139 | |||
| 140 | } | ||
| 141 | |||
| 142 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, | ||
| 143 | struct drm_device *drm, | ||
| 144 | unsigned int size, | ||
| 145 | unsigned int *handle) | ||
| 146 | { | ||
| 147 | struct tegra_bo *bo; | ||
| 148 | int ret; | ||
| 149 | |||
| 150 | bo = tegra_bo_create(drm, size); | ||
| 151 | if (IS_ERR(bo)) | ||
| 152 | return bo; | ||
| 153 | |||
| 154 | ret = drm_gem_handle_create(file, &bo->gem, handle); | ||
| 155 | if (ret) | ||
| 156 | goto err; | ||
| 157 | |||
| 158 | drm_gem_object_unreference_unlocked(&bo->gem); | ||
| 159 | |||
| 160 | return bo; | ||
| 161 | |||
| 162 | err: | ||
| 163 | tegra_bo_free_object(&bo->gem); | ||
| 164 | return ERR_PTR(ret); | ||
| 165 | } | ||
| 166 | |||
| 167 | void tegra_bo_free_object(struct drm_gem_object *gem) | ||
| 168 | { | ||
| 169 | struct tegra_bo *bo = to_tegra_bo(gem); | ||
| 170 | |||
| 171 | drm_gem_free_mmap_offset(gem); | ||
| 172 | drm_gem_object_release(gem); | ||
| 173 | tegra_bo_destroy(gem->dev, bo); | ||
| 174 | |||
| 175 | kfree(bo); | ||
| 176 | } | ||
| 177 | |||
| 178 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | ||
| 179 | struct drm_mode_create_dumb *args) | ||
| 180 | { | ||
| 181 | int min_pitch = DIV_ROUND_UP(args->width * args->bpp, 8); | ||
| 182 | struct tegra_bo *bo; | ||
| 183 | |||
| 184 | if (args->pitch < min_pitch) | ||
| 185 | args->pitch = min_pitch; | ||
| 186 | |||
| 187 | if (args->size < args->pitch * args->height) | ||
| 188 | args->size = args->pitch * args->height; | ||
| 189 | |||
| 190 | bo = tegra_bo_create_with_handle(file, drm, args->size, | ||
| 191 | &args->handle); | ||
| 192 | if (IS_ERR(bo)) | ||
| 193 | return PTR_ERR(bo); | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | ||
| 199 | uint32_t handle, uint64_t *offset) | ||
| 200 | { | ||
| 201 | struct drm_gem_object *gem; | ||
| 202 | struct tegra_bo *bo; | ||
| 203 | |||
| 204 | mutex_lock(&drm->struct_mutex); | ||
| 205 | |||
| 206 | gem = drm_gem_object_lookup(drm, file, handle); | ||
| 207 | if (!gem) { | ||
| 208 | dev_err(drm->dev, "failed to lookup GEM object\n"); | ||
| 209 | mutex_unlock(&drm->struct_mutex); | ||
| 210 | return -EINVAL; | ||
| 211 | } | ||
| 212 | |||
| 213 | bo = to_tegra_bo(gem); | ||
| 214 | |||
| 215 | *offset = drm_vma_node_offset_addr(&bo->gem.vma_node); | ||
| 216 | |||
| 217 | drm_gem_object_unreference(gem); | ||
| 218 | |||
| 219 | mutex_unlock(&drm->struct_mutex); | ||
| 220 | |||
| 221 | return 0; | ||
| 222 | } | ||
| 223 | |||
| 224 | const struct vm_operations_struct tegra_bo_vm_ops = { | ||
| 225 | .open = drm_gem_vm_open, | ||
| 226 | .close = drm_gem_vm_close, | ||
| 227 | }; | ||
| 228 | |||
| 229 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) | ||
| 230 | { | ||
| 231 | struct drm_gem_object *gem; | ||
| 232 | struct tegra_bo *bo; | ||
| 233 | int ret; | ||
| 234 | |||
| 235 | ret = drm_gem_mmap(file, vma); | ||
| 236 | if (ret) | ||
| 237 | return ret; | ||
| 238 | |||
| 239 | gem = vma->vm_private_data; | ||
| 240 | bo = to_tegra_bo(gem); | ||
| 241 | |||
| 242 | ret = remap_pfn_range(vma, vma->vm_start, bo->paddr >> PAGE_SHIFT, | ||
| 243 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
| 244 | if (ret) | ||
| 245 | drm_gem_vm_close(vma); | ||
| 246 | |||
| 247 | return ret; | ||
| 248 | } | ||
diff --git a/drivers/gpu/host1x/drm/gem.h b/drivers/gpu/host1x/drm/gem.h deleted file mode 100644 index 2b54f1425d5e..000000000000 --- a/drivers/gpu/host1x/drm/gem.h +++ /dev/null | |||
| @@ -1,56 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Tegra host1x GEM implementation | ||
| 3 | * | ||
| 4 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify it | ||
| 7 | * under the terms and conditions of the GNU General Public License, | ||
| 8 | * version 2, as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 13 | * more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #ifndef __HOST1X_GEM_H | ||
| 20 | #define __HOST1X_GEM_H | ||
| 21 | |||
| 22 | #include <linux/host1x.h> | ||
| 23 | |||
| 24 | #include <drm/drm.h> | ||
| 25 | #include <drm/drmP.h> | ||
| 26 | |||
| 27 | struct tegra_bo { | ||
| 28 | struct drm_gem_object gem; | ||
| 29 | struct host1x_bo base; | ||
| 30 | dma_addr_t paddr; | ||
| 31 | void *vaddr; | ||
| 32 | }; | ||
| 33 | |||
| 34 | static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem) | ||
| 35 | { | ||
| 36 | return container_of(gem, struct tegra_bo, gem); | ||
| 37 | } | ||
| 38 | |||
| 39 | extern const struct host1x_bo_ops tegra_bo_ops; | ||
| 40 | |||
| 41 | struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size); | ||
| 42 | struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file, | ||
| 43 | struct drm_device *drm, | ||
| 44 | unsigned int size, | ||
| 45 | unsigned int *handle); | ||
| 46 | void tegra_bo_free_object(struct drm_gem_object *gem); | ||
| 47 | int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, | ||
| 48 | struct drm_mode_create_dumb *args); | ||
| 49 | int tegra_bo_dumb_map_offset(struct drm_file *file, struct drm_device *drm, | ||
| 50 | uint32_t handle, uint64_t *offset); | ||
| 51 | |||
| 52 | int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); | ||
| 53 | |||
| 54 | extern const struct vm_operations_struct tegra_bo_vm_ops; | ||
| 55 | |||
| 56 | #endif | ||
diff --git a/drivers/gpu/host1x/drm/gr2d.c b/drivers/gpu/host1x/drm/gr2d.c deleted file mode 100644 index 4e407e30da1c..000000000000 --- a/drivers/gpu/host1x/drm/gr2d.c +++ /dev/null | |||
| @@ -1,343 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2012-2013, NVIDIA Corporation. | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/clk.h> | ||
| 18 | |||
| 19 | #include "drm.h" | ||
| 20 | #include "gem.h" | ||
| 21 | |||
| 22 | #define GR2D_NUM_REGS 0x4d | ||
| 23 | |||
| 24 | struct gr2d { | ||
| 25 | struct tegra_drm_client client; | ||
| 26 | struct host1x_channel *channel; | ||
| 27 | struct clk *clk; | ||
| 28 | |||
| 29 | DECLARE_BITMAP(addr_regs, GR2D_NUM_REGS); | ||
| 30 | }; | ||
| 31 | |||
| 32 | static inline struct gr2d *to_gr2d(struct tegra_drm_client *client) | ||
| 33 | { | ||
| 34 | return container_of(client, struct gr2d, client); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int gr2d_init(struct host1x_client *client) | ||
| 38 | { | ||
| 39 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | ||
| 40 | struct tegra_drm *tegra = dev_get_drvdata(client->parent); | ||
| 41 | struct gr2d *gr2d = to_gr2d(drm); | ||
| 42 | |||
| 43 | gr2d->channel = host1x_channel_request(client->dev); | ||
| 44 | if (!gr2d->channel) | ||
| 45 | return -ENOMEM; | ||
| 46 | |||
| 47 | client->syncpts[0] = host1x_syncpt_request(client->dev, false); | ||
| 48 | if (!client->syncpts[0]) { | ||
| 49 | host1x_channel_free(gr2d->channel); | ||
| 50 | return -ENOMEM; | ||
| 51 | } | ||
| 52 | |||
| 53 | return tegra_drm_register_client(tegra, drm); | ||
| 54 | } | ||
| 55 | |||
| 56 | static int gr2d_exit(struct host1x_client *client) | ||
| 57 | { | ||
| 58 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | ||
| 59 | struct tegra_drm *tegra = dev_get_drvdata(client->parent); | ||
| 60 | struct gr2d *gr2d = to_gr2d(drm); | ||
| 61 | int err; | ||
| 62 | |||
| 63 | err = tegra_drm_unregister_client(tegra, drm); | ||
| 64 | if (err < 0) | ||
| 65 | return err; | ||
| 66 | |||
| 67 | host1x_syncpt_free(client->syncpts[0]); | ||
| 68 | host1x_channel_free(gr2d->channel); | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static const struct host1x_client_ops gr2d_client_ops = { | ||
| 74 | .init = gr2d_init, | ||
| 75 | .exit = gr2d_exit, | ||
| 76 | }; | ||
| 77 | |||
| 78 | static int gr2d_open_channel(struct tegra_drm_client *client, | ||
| 79 | struct tegra_drm_context *context) | ||
| 80 | { | ||
| 81 | struct gr2d *gr2d = to_gr2d(client); | ||
| 82 | |||
| 83 | context->channel = host1x_channel_get(gr2d->channel); | ||
| 84 | if (!context->channel) | ||
| 85 | return -ENOMEM; | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static void gr2d_close_channel(struct tegra_drm_context *context) | ||
| 91 | { | ||
| 92 | host1x_channel_put(context->channel); | ||
| 93 | } | ||
| 94 | |||
| 95 | static struct host1x_bo *host1x_bo_lookup(struct drm_device *drm, | ||
| 96 | struct drm_file *file, | ||
| 97 | u32 handle) | ||
| 98 | { | ||
| 99 | struct drm_gem_object *gem; | ||
| 100 | struct tegra_bo *bo; | ||
| 101 | |||
| 102 | gem = drm_gem_object_lookup(drm, file, handle); | ||
| 103 | if (!gem) | ||
| 104 | return NULL; | ||
| 105 | |||
| 106 | mutex_lock(&drm->struct_mutex); | ||
| 107 | drm_gem_object_unreference(gem); | ||
| 108 | mutex_unlock(&drm->struct_mutex); | ||
| 109 | |||
| 110 | bo = to_tegra_bo(gem); | ||
| 111 | return &bo->base; | ||
| 112 | } | ||
| 113 | |||
| 114 | static int gr2d_is_addr_reg(struct device *dev, u32 class, u32 offset) | ||
| 115 | { | ||
| 116 | struct gr2d *gr2d = dev_get_drvdata(dev); | ||
| 117 | |||
| 118 | switch (class) { | ||
| 119 | case HOST1X_CLASS_HOST1X: | ||
| 120 | if (offset == 0x2b) | ||
| 121 | return 1; | ||
| 122 | |||
| 123 | break; | ||
| 124 | |||
| 125 | case HOST1X_CLASS_GR2D: | ||
| 126 | case HOST1X_CLASS_GR2D_SB: | ||
| 127 | if (offset >= GR2D_NUM_REGS) | ||
| 128 | break; | ||
| 129 | |||
| 130 | if (test_bit(offset, gr2d->addr_regs)) | ||
| 131 | return 1; | ||
| 132 | |||
| 133 | break; | ||
| 134 | } | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | static int gr2d_submit(struct tegra_drm_context *context, | ||
| 140 | struct drm_tegra_submit *args, struct drm_device *drm, | ||
| 141 | struct drm_file *file) | ||
| 142 | { | ||
| 143 | unsigned int num_cmdbufs = args->num_cmdbufs; | ||
| 144 | unsigned int num_relocs = args->num_relocs; | ||
| 145 | unsigned int num_waitchks = args->num_waitchks; | ||
| 146 | struct drm_tegra_cmdbuf __user *cmdbufs = | ||
| 147 | (void * __user)(uintptr_t)args->cmdbufs; | ||
| 148 | struct drm_tegra_reloc __user *relocs = | ||
| 149 | (void * __user)(uintptr_t)args->relocs; | ||
| 150 | struct drm_tegra_waitchk __user *waitchks = | ||
| 151 | (void * __user)(uintptr_t)args->waitchks; | ||
| 152 | struct drm_tegra_syncpt syncpt; | ||
| 153 | struct host1x_job *job; | ||
| 154 | int err; | ||
| 155 | |||
| 156 | /* We don't yet support other than one syncpt_incr struct per submit */ | ||
| 157 | if (args->num_syncpts != 1) | ||
| 158 | return -EINVAL; | ||
| 159 | |||
| 160 | job = host1x_job_alloc(context->channel, args->num_cmdbufs, | ||
| 161 | args->num_relocs, args->num_waitchks); | ||
| 162 | if (!job) | ||
| 163 | return -ENOMEM; | ||
| 164 | |||
| 165 | job->num_relocs = args->num_relocs; | ||
| 166 | job->num_waitchk = args->num_waitchks; | ||
| 167 | job->client = (u32)args->context; | ||
| 168 | job->class = context->client->base.class; | ||
| 169 | job->serialize = true; | ||
| 170 | |||
| 171 | while (num_cmdbufs) { | ||
| 172 | struct drm_tegra_cmdbuf cmdbuf; | ||
| 173 | struct host1x_bo *bo; | ||
| 174 | |||
| 175 | err = copy_from_user(&cmdbuf, cmdbufs, sizeof(cmdbuf)); | ||
| 176 | if (err) | ||
| 177 | goto fail; | ||
| 178 | |||
| 179 | bo = host1x_bo_lookup(drm, file, cmdbuf.handle); | ||
| 180 | if (!bo) { | ||
| 181 | err = -ENOENT; | ||
| 182 | goto fail; | ||
| 183 | } | ||
| 184 | |||
| 185 | host1x_job_add_gather(job, bo, cmdbuf.words, cmdbuf.offset); | ||
| 186 | num_cmdbufs--; | ||
| 187 | cmdbufs++; | ||
| 188 | } | ||
| 189 | |||
| 190 | err = copy_from_user(job->relocarray, relocs, | ||
| 191 | sizeof(*relocs) * num_relocs); | ||
| 192 | if (err) | ||
| 193 | goto fail; | ||
| 194 | |||
| 195 | while (num_relocs--) { | ||
| 196 | struct host1x_reloc *reloc = &job->relocarray[num_relocs]; | ||
| 197 | struct host1x_bo *cmdbuf, *target; | ||
| 198 | |||
| 199 | cmdbuf = host1x_bo_lookup(drm, file, (u32)reloc->cmdbuf); | ||
| 200 | target = host1x_bo_lookup(drm, file, (u32)reloc->target); | ||
| 201 | |||
| 202 | reloc->cmdbuf = cmdbuf; | ||
| 203 | reloc->target = target; | ||
| 204 | |||
| 205 | if (!reloc->target || !reloc->cmdbuf) { | ||
| 206 | err = -ENOENT; | ||
| 207 | goto fail; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | |||
| 211 | err = copy_from_user(job->waitchk, waitchks, | ||
| 212 | sizeof(*waitchks) * num_waitchks); | ||
| 213 | if (err) | ||
| 214 | goto fail; | ||
| 215 | |||
| 216 | err = copy_from_user(&syncpt, (void * __user)(uintptr_t)args->syncpts, | ||
| 217 | sizeof(syncpt)); | ||
| 218 | if (err) | ||
| 219 | goto fail; | ||
| 220 | |||
| 221 | job->syncpt_id = syncpt.id; | ||
| 222 | job->syncpt_incrs = syncpt.incrs; | ||
| 223 | job->timeout = 10000; | ||
| 224 | job->is_addr_reg = gr2d_is_addr_reg; | ||
| 225 | |||
| 226 | if (args->timeout && args->timeout < 10000) | ||
| 227 | job->timeout = args->timeout; | ||
| 228 | |||
| 229 | err = host1x_job_pin(job, context->client->base.dev); | ||
| 230 | if (err) | ||
| 231 | goto fail; | ||
| 232 | |||
| 233 | err = host1x_job_submit(job); | ||
| 234 | if (err) | ||
| 235 | goto fail_submit; | ||
| 236 | |||
| 237 | args->fence = job->syncpt_end; | ||
| 238 | |||
| 239 | host1x_job_put(job); | ||
| 240 | return 0; | ||
| 241 | |||
| 242 | fail_submit: | ||
| 243 | host1x_job_unpin(job); | ||
| 244 | fail: | ||
| 245 | host1x_job_put(job); | ||
| 246 | return err; | ||
| 247 | } | ||
| 248 | |||
| 249 | static const struct tegra_drm_client_ops gr2d_ops = { | ||
| 250 | .open_channel = gr2d_open_channel, | ||
| 251 | .close_channel = gr2d_close_channel, | ||
| 252 | .submit = gr2d_submit, | ||
| 253 | }; | ||
| 254 | |||
| 255 | static const struct of_device_id gr2d_match[] = { | ||
| 256 | { .compatible = "nvidia,tegra30-gr2d" }, | ||
| 257 | { .compatible = "nvidia,tegra20-gr2d" }, | ||
| 258 | { }, | ||
| 259 | }; | ||
| 260 | |||
| 261 | static const u32 gr2d_addr_regs[] = { | ||
| 262 | 0x1a, 0x1b, 0x26, 0x2b, 0x2c, 0x2d, 0x31, 0x32, | ||
| 263 | 0x48, 0x49, 0x4a, 0x4b, 0x4c | ||
| 264 | }; | ||
| 265 | |||
| 266 | static int gr2d_probe(struct platform_device *pdev) | ||
| 267 | { | ||
| 268 | struct device *dev = &pdev->dev; | ||
| 269 | struct host1x_syncpt **syncpts; | ||
| 270 | struct gr2d *gr2d; | ||
| 271 | unsigned int i; | ||
| 272 | int err; | ||
| 273 | |||
| 274 | gr2d = devm_kzalloc(dev, sizeof(*gr2d), GFP_KERNEL); | ||
| 275 | if (!gr2d) | ||
| 276 | return -ENOMEM; | ||
| 277 | |||
| 278 | syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); | ||
| 279 | if (!syncpts) | ||
| 280 | return -ENOMEM; | ||
| 281 | |||
| 282 | gr2d->clk = devm_clk_get(dev, NULL); | ||
| 283 | if (IS_ERR(gr2d->clk)) { | ||
| 284 | dev_err(dev, "cannot get clock\n"); | ||
| 285 | return PTR_ERR(gr2d->clk); | ||
| 286 | } | ||
| 287 | |||
| 288 | err = clk_prepare_enable(gr2d->clk); | ||
| 289 | if (err) { | ||
| 290 | dev_err(dev, "cannot turn on clock\n"); | ||
| 291 | return err; | ||
| 292 | } | ||
| 293 | |||
| 294 | INIT_LIST_HEAD(&gr2d->client.base.list); | ||
| 295 | gr2d->client.base.ops = &gr2d_client_ops; | ||
| 296 | gr2d->client.base.dev = dev; | ||
| 297 | gr2d->client.base.class = HOST1X_CLASS_GR2D; | ||
| 298 | gr2d->client.base.syncpts = syncpts; | ||
| 299 | gr2d->client.base.num_syncpts = 1; | ||
| 300 | |||
| 301 | INIT_LIST_HEAD(&gr2d->client.list); | ||
| 302 | gr2d->client.ops = &gr2d_ops; | ||
| 303 | |||
| 304 | err = host1x_client_register(&gr2d->client.base); | ||
| 305 | if (err < 0) { | ||
| 306 | dev_err(dev, "failed to register host1x client: %d\n", err); | ||
| 307 | return err; | ||
| 308 | } | ||
| 309 | |||
| 310 | /* initialize address register map */ | ||
| 311 | for (i = 0; i < ARRAY_SIZE(gr2d_addr_regs); i++) | ||
| 312 | set_bit(gr2d_addr_regs[i], gr2d->addr_regs); | ||
| 313 | |||
| 314 | platform_set_drvdata(pdev, gr2d); | ||
| 315 | |||
| 316 | return 0; | ||
| 317 | } | ||
| 318 | |||
| 319 | static int gr2d_remove(struct platform_device *pdev) | ||
| 320 | { | ||
| 321 | struct gr2d *gr2d = platform_get_drvdata(pdev); | ||
| 322 | int err; | ||
| 323 | |||
| 324 | err = host1x_client_unregister(&gr2d->client.base); | ||
| 325 | if (err < 0) { | ||
| 326 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | ||
| 327 | err); | ||
| 328 | return err; | ||
| 329 | } | ||
| 330 | |||
| 331 | clk_disable_unprepare(gr2d->clk); | ||
| 332 | |||
| 333 | return 0; | ||
| 334 | } | ||
| 335 | |||
| 336 | struct platform_driver tegra_gr2d_driver = { | ||
| 337 | .driver = { | ||
| 338 | .name = "tegra-gr2d", | ||
| 339 | .of_match_table = gr2d_match, | ||
| 340 | }, | ||
| 341 | .probe = gr2d_probe, | ||
| 342 | .remove = gr2d_remove, | ||
| 343 | }; | ||
diff --git a/drivers/gpu/host1x/drm/hdmi.c b/drivers/gpu/host1x/drm/hdmi.c deleted file mode 100644 index f5663d15670b..000000000000 --- a/drivers/gpu/host1x/drm/hdmi.c +++ /dev/null | |||
| @@ -1,1295 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/clk.h> | ||
| 11 | #include <linux/clk/tegra.h> | ||
| 12 | #include <linux/debugfs.h> | ||
| 13 | #include <linux/hdmi.h> | ||
| 14 | #include <linux/regulator/consumer.h> | ||
| 15 | |||
| 16 | #include "hdmi.h" | ||
| 17 | #include "drm.h" | ||
| 18 | #include "dc.h" | ||
| 19 | |||
| 20 | struct tegra_hdmi { | ||
| 21 | struct host1x_client client; | ||
| 22 | struct tegra_output output; | ||
| 23 | struct device *dev; | ||
| 24 | |||
| 25 | struct regulator *vdd; | ||
| 26 | struct regulator *pll; | ||
| 27 | |||
| 28 | void __iomem *regs; | ||
| 29 | unsigned int irq; | ||
| 30 | |||
| 31 | struct clk *clk_parent; | ||
| 32 | struct clk *clk; | ||
| 33 | |||
| 34 | unsigned int audio_source; | ||
| 35 | unsigned int audio_freq; | ||
| 36 | bool stereo; | ||
| 37 | bool dvi; | ||
| 38 | |||
| 39 | struct drm_info_list *debugfs_files; | ||
| 40 | struct drm_minor *minor; | ||
| 41 | struct dentry *debugfs; | ||
| 42 | }; | ||
| 43 | |||
| 44 | static inline struct tegra_hdmi * | ||
| 45 | host1x_client_to_hdmi(struct host1x_client *client) | ||
| 46 | { | ||
| 47 | return container_of(client, struct tegra_hdmi, client); | ||
| 48 | } | ||
| 49 | |||
| 50 | static inline struct tegra_hdmi *to_hdmi(struct tegra_output *output) | ||
| 51 | { | ||
| 52 | return container_of(output, struct tegra_hdmi, output); | ||
| 53 | } | ||
| 54 | |||
| 55 | #define HDMI_AUDIOCLK_FREQ 216000000 | ||
| 56 | #define HDMI_REKEY_DEFAULT 56 | ||
| 57 | |||
| 58 | enum { | ||
| 59 | AUTO = 0, | ||
| 60 | SPDIF, | ||
| 61 | HDA, | ||
| 62 | }; | ||
| 63 | |||
| 64 | static inline unsigned long tegra_hdmi_readl(struct tegra_hdmi *hdmi, | ||
| 65 | unsigned long reg) | ||
| 66 | { | ||
| 67 | return readl(hdmi->regs + (reg << 2)); | ||
| 68 | } | ||
| 69 | |||
| 70 | static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, unsigned long val, | ||
| 71 | unsigned long reg) | ||
| 72 | { | ||
| 73 | writel(val, hdmi->regs + (reg << 2)); | ||
| 74 | } | ||
| 75 | |||
| 76 | struct tegra_hdmi_audio_config { | ||
| 77 | unsigned int pclk; | ||
| 78 | unsigned int n; | ||
| 79 | unsigned int cts; | ||
| 80 | unsigned int aval; | ||
| 81 | }; | ||
| 82 | |||
| 83 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = { | ||
| 84 | { 25200000, 4096, 25200, 24000 }, | ||
| 85 | { 27000000, 4096, 27000, 24000 }, | ||
| 86 | { 74250000, 4096, 74250, 24000 }, | ||
| 87 | { 148500000, 4096, 148500, 24000 }, | ||
| 88 | { 0, 0, 0, 0 }, | ||
| 89 | }; | ||
| 90 | |||
| 91 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = { | ||
| 92 | { 25200000, 5880, 26250, 25000 }, | ||
| 93 | { 27000000, 5880, 28125, 25000 }, | ||
| 94 | { 74250000, 4704, 61875, 20000 }, | ||
| 95 | { 148500000, 4704, 123750, 20000 }, | ||
| 96 | { 0, 0, 0, 0 }, | ||
| 97 | }; | ||
| 98 | |||
| 99 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = { | ||
| 100 | { 25200000, 6144, 25200, 24000 }, | ||
| 101 | { 27000000, 6144, 27000, 24000 }, | ||
| 102 | { 74250000, 6144, 74250, 24000 }, | ||
| 103 | { 148500000, 6144, 148500, 24000 }, | ||
| 104 | { 0, 0, 0, 0 }, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = { | ||
| 108 | { 25200000, 11760, 26250, 25000 }, | ||
| 109 | { 27000000, 11760, 28125, 25000 }, | ||
| 110 | { 74250000, 9408, 61875, 20000 }, | ||
| 111 | { 148500000, 9408, 123750, 20000 }, | ||
| 112 | { 0, 0, 0, 0 }, | ||
| 113 | }; | ||
| 114 | |||
| 115 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = { | ||
| 116 | { 25200000, 12288, 25200, 24000 }, | ||
| 117 | { 27000000, 12288, 27000, 24000 }, | ||
| 118 | { 74250000, 12288, 74250, 24000 }, | ||
| 119 | { 148500000, 12288, 148500, 24000 }, | ||
| 120 | { 0, 0, 0, 0 }, | ||
| 121 | }; | ||
| 122 | |||
| 123 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = { | ||
| 124 | { 25200000, 23520, 26250, 25000 }, | ||
| 125 | { 27000000, 23520, 28125, 25000 }, | ||
| 126 | { 74250000, 18816, 61875, 20000 }, | ||
| 127 | { 148500000, 18816, 123750, 20000 }, | ||
| 128 | { 0, 0, 0, 0 }, | ||
| 129 | }; | ||
| 130 | |||
| 131 | static const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = { | ||
| 132 | { 25200000, 24576, 25200, 24000 }, | ||
| 133 | { 27000000, 24576, 27000, 24000 }, | ||
| 134 | { 74250000, 24576, 74250, 24000 }, | ||
| 135 | { 148500000, 24576, 148500, 24000 }, | ||
| 136 | { 0, 0, 0, 0 }, | ||
| 137 | }; | ||
| 138 | |||
| 139 | struct tmds_config { | ||
| 140 | unsigned int pclk; | ||
| 141 | u32 pll0; | ||
| 142 | u32 pll1; | ||
| 143 | u32 pe_current; | ||
| 144 | u32 drive_current; | ||
| 145 | }; | ||
| 146 | |||
| 147 | static const struct tmds_config tegra2_tmds_config[] = { | ||
| 148 | { /* slow pixel clock modes */ | ||
| 149 | .pclk = 27000000, | ||
| 150 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
| 151 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) | | ||
| 152 | SOR_PLL_TX_REG_LOAD(3), | ||
| 153 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE, | ||
| 154 | .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) | | ||
| 155 | PE_CURRENT1(PE_CURRENT_0_0_mA) | | ||
| 156 | PE_CURRENT2(PE_CURRENT_0_0_mA) | | ||
| 157 | PE_CURRENT3(PE_CURRENT_0_0_mA), | ||
| 158 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
| 159 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
| 160 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
| 161 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
| 162 | }, | ||
| 163 | { /* high pixel clock modes */ | ||
| 164 | .pclk = UINT_MAX, | ||
| 165 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
| 166 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) | | ||
| 167 | SOR_PLL_TX_REG_LOAD(3), | ||
| 168 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
| 169 | .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) | | ||
| 170 | PE_CURRENT1(PE_CURRENT_6_0_mA) | | ||
| 171 | PE_CURRENT2(PE_CURRENT_6_0_mA) | | ||
| 172 | PE_CURRENT3(PE_CURRENT_6_0_mA), | ||
| 173 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) | | ||
| 174 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) | | ||
| 175 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) | | ||
| 176 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA), | ||
| 177 | }, | ||
| 178 | }; | ||
| 179 | |||
| 180 | static const struct tmds_config tegra3_tmds_config[] = { | ||
| 181 | { /* 480p modes */ | ||
| 182 | .pclk = 27000000, | ||
| 183 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
| 184 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(0) | | ||
| 185 | SOR_PLL_TX_REG_LOAD(0), | ||
| 186 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE, | ||
| 187 | .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) | | ||
| 188 | PE_CURRENT1(PE_CURRENT_0_0_mA) | | ||
| 189 | PE_CURRENT2(PE_CURRENT_0_0_mA) | | ||
| 190 | PE_CURRENT3(PE_CURRENT_0_0_mA), | ||
| 191 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
| 192 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
| 193 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
| 194 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
| 195 | }, { /* 720p modes */ | ||
| 196 | .pclk = 74250000, | ||
| 197 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
| 198 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(1) | | ||
| 199 | SOR_PLL_TX_REG_LOAD(0), | ||
| 200 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
| 201 | .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) | | ||
| 202 | PE_CURRENT1(PE_CURRENT_5_0_mA) | | ||
| 203 | PE_CURRENT2(PE_CURRENT_5_0_mA) | | ||
| 204 | PE_CURRENT3(PE_CURRENT_5_0_mA), | ||
| 205 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
| 206 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
| 207 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
| 208 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
| 209 | }, { /* 1080p modes */ | ||
| 210 | .pclk = UINT_MAX, | ||
| 211 | .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | | ||
| 212 | SOR_PLL_RESISTORSEL | SOR_PLL_VCOCAP(3) | | ||
| 213 | SOR_PLL_TX_REG_LOAD(0), | ||
| 214 | .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN, | ||
| 215 | .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) | | ||
| 216 | PE_CURRENT1(PE_CURRENT_5_0_mA) | | ||
| 217 | PE_CURRENT2(PE_CURRENT_5_0_mA) | | ||
| 218 | PE_CURRENT3(PE_CURRENT_5_0_mA), | ||
| 219 | .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) | | ||
| 220 | DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) | | ||
| 221 | DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) | | ||
| 222 | DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA), | ||
| 223 | }, | ||
| 224 | }; | ||
| 225 | |||
| 226 | static const struct tegra_hdmi_audio_config * | ||
| 227 | tegra_hdmi_get_audio_config(unsigned int audio_freq, unsigned int pclk) | ||
| 228 | { | ||
| 229 | const struct tegra_hdmi_audio_config *table; | ||
| 230 | |||
| 231 | switch (audio_freq) { | ||
| 232 | case 32000: | ||
| 233 | table = tegra_hdmi_audio_32k; | ||
| 234 | break; | ||
| 235 | |||
| 236 | case 44100: | ||
| 237 | table = tegra_hdmi_audio_44_1k; | ||
| 238 | break; | ||
| 239 | |||
| 240 | case 48000: | ||
| 241 | table = tegra_hdmi_audio_48k; | ||
| 242 | break; | ||
| 243 | |||
| 244 | case 88200: | ||
| 245 | table = tegra_hdmi_audio_88_2k; | ||
| 246 | break; | ||
| 247 | |||
| 248 | case 96000: | ||
| 249 | table = tegra_hdmi_audio_96k; | ||
| 250 | break; | ||
| 251 | |||
| 252 | case 176400: | ||
| 253 | table = tegra_hdmi_audio_176_4k; | ||
| 254 | break; | ||
| 255 | |||
| 256 | case 192000: | ||
| 257 | table = tegra_hdmi_audio_192k; | ||
| 258 | break; | ||
| 259 | |||
| 260 | default: | ||
| 261 | return NULL; | ||
| 262 | } | ||
| 263 | |||
| 264 | while (table->pclk) { | ||
| 265 | if (table->pclk == pclk) | ||
| 266 | return table; | ||
| 267 | |||
| 268 | table++; | ||
| 269 | } | ||
| 270 | |||
| 271 | return NULL; | ||
| 272 | } | ||
| 273 | |||
| 274 | static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi) | ||
| 275 | { | ||
| 276 | const unsigned int freqs[] = { | ||
| 277 | 32000, 44100, 48000, 88200, 96000, 176400, 192000 | ||
| 278 | }; | ||
| 279 | unsigned int i; | ||
| 280 | |||
| 281 | for (i = 0; i < ARRAY_SIZE(freqs); i++) { | ||
| 282 | unsigned int f = freqs[i]; | ||
| 283 | unsigned int eight_half; | ||
| 284 | unsigned long value; | ||
| 285 | unsigned int delta; | ||
| 286 | |||
| 287 | if (f > 96000) | ||
| 288 | delta = 2; | ||
| 289 | else if (f > 480000) | ||
| 290 | delta = 6; | ||
| 291 | else | ||
| 292 | delta = 9; | ||
| 293 | |||
| 294 | eight_half = (8 * HDMI_AUDIOCLK_FREQ) / (f * 128); | ||
| 295 | value = AUDIO_FS_LOW(eight_half - delta) | | ||
| 296 | AUDIO_FS_HIGH(eight_half + delta); | ||
| 297 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_FS(i)); | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk) | ||
| 302 | { | ||
| 303 | struct device_node *node = hdmi->dev->of_node; | ||
| 304 | const struct tegra_hdmi_audio_config *config; | ||
| 305 | unsigned int offset = 0; | ||
| 306 | unsigned long value; | ||
| 307 | |||
| 308 | switch (hdmi->audio_source) { | ||
| 309 | case HDA: | ||
| 310 | value = AUDIO_CNTRL0_SOURCE_SELECT_HDAL; | ||
| 311 | break; | ||
| 312 | |||
| 313 | case SPDIF: | ||
| 314 | value = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF; | ||
| 315 | break; | ||
| 316 | |||
| 317 | default: | ||
| 318 | value = AUDIO_CNTRL0_SOURCE_SELECT_AUTO; | ||
| 319 | break; | ||
| 320 | } | ||
| 321 | |||
| 322 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | ||
| 323 | value |= AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | ||
| 324 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0); | ||
| 325 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
| 326 | } else { | ||
| 327 | value |= AUDIO_CNTRL0_INJECT_NULLSMPL; | ||
| 328 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); | ||
| 329 | |||
| 330 | value = AUDIO_CNTRL0_ERROR_TOLERANCE(6) | | ||
| 331 | AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0); | ||
| 332 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
| 333 | } | ||
| 334 | |||
| 335 | config = tegra_hdmi_get_audio_config(hdmi->audio_freq, pclk); | ||
| 336 | if (!config) { | ||
| 337 | dev_err(hdmi->dev, "cannot set audio to %u at %u pclk\n", | ||
| 338 | hdmi->audio_freq, pclk); | ||
| 339 | return -EINVAL; | ||
| 340 | } | ||
| 341 | |||
| 342 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL); | ||
| 343 | |||
| 344 | value = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNATE | | ||
| 345 | AUDIO_N_VALUE(config->n - 1); | ||
| 346 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); | ||
| 347 | |||
| 348 | tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE, | ||
| 349 | HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | ||
| 350 | |||
| 351 | value = ACR_SUBPACK_CTS(config->cts); | ||
| 352 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | ||
| 353 | |||
| 354 | value = SPARE_HW_CTS | SPARE_FORCE_SW_CTS | SPARE_CTS_RESET_VAL(1); | ||
| 355 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_SPARE); | ||
| 356 | |||
| 357 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_AUDIO_N); | ||
| 358 | value &= ~AUDIO_N_RESETF; | ||
| 359 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_AUDIO_N); | ||
| 360 | |||
| 361 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | ||
| 362 | switch (hdmi->audio_freq) { | ||
| 363 | case 32000: | ||
| 364 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320; | ||
| 365 | break; | ||
| 366 | |||
| 367 | case 44100: | ||
| 368 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441; | ||
| 369 | break; | ||
| 370 | |||
| 371 | case 48000: | ||
| 372 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480; | ||
| 373 | break; | ||
| 374 | |||
| 375 | case 88200: | ||
| 376 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882; | ||
| 377 | break; | ||
| 378 | |||
| 379 | case 96000: | ||
| 380 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960; | ||
| 381 | break; | ||
| 382 | |||
| 383 | case 176400: | ||
| 384 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764; | ||
| 385 | break; | ||
| 386 | |||
| 387 | case 192000: | ||
| 388 | offset = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920; | ||
| 389 | break; | ||
| 390 | } | ||
| 391 | |||
| 392 | tegra_hdmi_writel(hdmi, config->aval, offset); | ||
| 393 | } | ||
| 394 | |||
| 395 | tegra_hdmi_setup_audio_fs_tables(hdmi); | ||
| 396 | |||
| 397 | return 0; | ||
| 398 | } | ||
| 399 | |||
| 400 | static inline unsigned long tegra_hdmi_subpack(const u8 *ptr, size_t size) | ||
| 401 | { | ||
| 402 | unsigned long value = 0; | ||
| 403 | size_t i; | ||
| 404 | |||
| 405 | for (i = size; i > 0; i--) | ||
| 406 | value = (value << 8) | ptr[i - 1]; | ||
| 407 | |||
| 408 | return value; | ||
| 409 | } | ||
| 410 | |||
| 411 | static void tegra_hdmi_write_infopack(struct tegra_hdmi *hdmi, const void *data, | ||
| 412 | size_t size) | ||
| 413 | { | ||
| 414 | const u8 *ptr = data; | ||
| 415 | unsigned long offset; | ||
| 416 | unsigned long value; | ||
| 417 | size_t i, j; | ||
| 418 | |||
| 419 | switch (ptr[0]) { | ||
| 420 | case HDMI_INFOFRAME_TYPE_AVI: | ||
| 421 | offset = HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER; | ||
| 422 | break; | ||
| 423 | |||
| 424 | case HDMI_INFOFRAME_TYPE_AUDIO: | ||
| 425 | offset = HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER; | ||
| 426 | break; | ||
| 427 | |||
| 428 | case HDMI_INFOFRAME_TYPE_VENDOR: | ||
| 429 | offset = HDMI_NV_PDISP_HDMI_GENERIC_HEADER; | ||
| 430 | break; | ||
| 431 | |||
| 432 | default: | ||
| 433 | dev_err(hdmi->dev, "unsupported infoframe type: %02x\n", | ||
| 434 | ptr[0]); | ||
| 435 | return; | ||
| 436 | } | ||
| 437 | |||
| 438 | value = INFOFRAME_HEADER_TYPE(ptr[0]) | | ||
| 439 | INFOFRAME_HEADER_VERSION(ptr[1]) | | ||
| 440 | INFOFRAME_HEADER_LEN(ptr[2]); | ||
| 441 | tegra_hdmi_writel(hdmi, value, offset); | ||
| 442 | offset++; | ||
| 443 | |||
| 444 | /* | ||
| 445 | * Each subpack contains 7 bytes, divided into: | ||
| 446 | * - subpack_low: bytes 0 - 3 | ||
| 447 | * - subpack_high: bytes 4 - 6 (with byte 7 padded to 0x00) | ||
| 448 | */ | ||
| 449 | for (i = 3, j = 0; i < size; i += 7, j += 8) { | ||
| 450 | size_t rem = size - i, num = min_t(size_t, rem, 4); | ||
| 451 | |||
| 452 | value = tegra_hdmi_subpack(&ptr[i], num); | ||
| 453 | tegra_hdmi_writel(hdmi, value, offset++); | ||
| 454 | |||
| 455 | num = min_t(size_t, rem - num, 3); | ||
| 456 | |||
| 457 | value = tegra_hdmi_subpack(&ptr[i + 4], num); | ||
| 458 | tegra_hdmi_writel(hdmi, value, offset++); | ||
| 459 | } | ||
| 460 | } | ||
| 461 | |||
| 462 | static void tegra_hdmi_setup_avi_infoframe(struct tegra_hdmi *hdmi, | ||
| 463 | struct drm_display_mode *mode) | ||
| 464 | { | ||
| 465 | struct hdmi_avi_infoframe frame; | ||
| 466 | u8 buffer[17]; | ||
| 467 | ssize_t err; | ||
| 468 | |||
| 469 | if (hdmi->dvi) { | ||
| 470 | tegra_hdmi_writel(hdmi, 0, | ||
| 471 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
| 472 | return; | ||
| 473 | } | ||
| 474 | |||
| 475 | err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode); | ||
| 476 | if (err < 0) { | ||
| 477 | dev_err(hdmi->dev, "failed to setup AVI infoframe: %zd\n", err); | ||
| 478 | return; | ||
| 479 | } | ||
| 480 | |||
| 481 | err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
| 482 | if (err < 0) { | ||
| 483 | dev_err(hdmi->dev, "failed to pack AVI infoframe: %zd\n", err); | ||
| 484 | return; | ||
| 485 | } | ||
| 486 | |||
| 487 | tegra_hdmi_write_infopack(hdmi, buffer, err); | ||
| 488 | |||
| 489 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | ||
| 490 | HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
| 491 | } | ||
| 492 | |||
| 493 | static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi) | ||
| 494 | { | ||
| 495 | struct hdmi_audio_infoframe frame; | ||
| 496 | u8 buffer[14]; | ||
| 497 | ssize_t err; | ||
| 498 | |||
| 499 | if (hdmi->dvi) { | ||
| 500 | tegra_hdmi_writel(hdmi, 0, | ||
| 501 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
| 502 | return; | ||
| 503 | } | ||
| 504 | |||
| 505 | err = hdmi_audio_infoframe_init(&frame); | ||
| 506 | if (err < 0) { | ||
| 507 | dev_err(hdmi->dev, "failed to initialize audio infoframe: %d\n", | ||
| 508 | err); | ||
| 509 | return; | ||
| 510 | } | ||
| 511 | |||
| 512 | frame.channels = 2; | ||
| 513 | |||
| 514 | err = hdmi_audio_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
| 515 | if (err < 0) { | ||
| 516 | dev_err(hdmi->dev, "failed to pack audio infoframe: %zd\n", | ||
| 517 | err); | ||
| 518 | return; | ||
| 519 | } | ||
| 520 | |||
| 521 | /* | ||
| 522 | * The audio infoframe has only one set of subpack registers, so the | ||
| 523 | * infoframe needs to be truncated. One set of subpack registers can | ||
| 524 | * contain 7 bytes. Including the 3 byte header only the first 10 | ||
| 525 | * bytes can be programmed. | ||
| 526 | */ | ||
| 527 | tegra_hdmi_write_infopack(hdmi, buffer, min(10, err)); | ||
| 528 | |||
| 529 | tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE, | ||
| 530 | HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
| 531 | } | ||
| 532 | |||
| 533 | static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi) | ||
| 534 | { | ||
| 535 | struct hdmi_vendor_infoframe frame; | ||
| 536 | unsigned long value; | ||
| 537 | u8 buffer[10]; | ||
| 538 | ssize_t err; | ||
| 539 | |||
| 540 | if (!hdmi->stereo) { | ||
| 541 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 542 | value &= ~GENERIC_CTRL_ENABLE; | ||
| 543 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 544 | return; | ||
| 545 | } | ||
| 546 | |||
| 547 | hdmi_vendor_infoframe_init(&frame); | ||
| 548 | frame.s3d_struct = HDMI_3D_STRUCTURE_FRAME_PACKING; | ||
| 549 | |||
| 550 | err = hdmi_vendor_infoframe_pack(&frame, buffer, sizeof(buffer)); | ||
| 551 | if (err < 0) { | ||
| 552 | dev_err(hdmi->dev, "failed to pack vendor infoframe: %zd\n", | ||
| 553 | err); | ||
| 554 | return; | ||
| 555 | } | ||
| 556 | |||
| 557 | tegra_hdmi_write_infopack(hdmi, buffer, err); | ||
| 558 | |||
| 559 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 560 | value |= GENERIC_CTRL_ENABLE; | ||
| 561 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 562 | } | ||
| 563 | |||
| 564 | static void tegra_hdmi_setup_tmds(struct tegra_hdmi *hdmi, | ||
| 565 | const struct tmds_config *tmds) | ||
| 566 | { | ||
| 567 | unsigned long value; | ||
| 568 | |||
| 569 | tegra_hdmi_writel(hdmi, tmds->pll0, HDMI_NV_PDISP_SOR_PLL0); | ||
| 570 | tegra_hdmi_writel(hdmi, tmds->pll1, HDMI_NV_PDISP_SOR_PLL1); | ||
| 571 | tegra_hdmi_writel(hdmi, tmds->pe_current, HDMI_NV_PDISP_PE_CURRENT); | ||
| 572 | |||
| 573 | value = tmds->drive_current | DRIVE_CURRENT_FUSE_OVERRIDE; | ||
| 574 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); | ||
| 575 | } | ||
| 576 | |||
| 577 | static int tegra_output_hdmi_enable(struct tegra_output *output) | ||
| 578 | { | ||
| 579 | unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey; | ||
| 580 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
| 581 | struct drm_display_mode *mode = &dc->base.mode; | ||
| 582 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
| 583 | struct device_node *node = hdmi->dev->of_node; | ||
| 584 | unsigned int pulse_start, div82, pclk; | ||
| 585 | const struct tmds_config *tmds; | ||
| 586 | unsigned int num_tmds; | ||
| 587 | unsigned long value; | ||
| 588 | int retries = 1000; | ||
| 589 | int err; | ||
| 590 | |||
| 591 | pclk = mode->clock * 1000; | ||
| 592 | h_sync_width = mode->hsync_end - mode->hsync_start; | ||
| 593 | h_back_porch = mode->htotal - mode->hsync_end; | ||
| 594 | h_front_porch = mode->hsync_start - mode->hdisplay; | ||
| 595 | |||
| 596 | err = regulator_enable(hdmi->vdd); | ||
| 597 | if (err < 0) { | ||
| 598 | dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err); | ||
| 599 | return err; | ||
| 600 | } | ||
| 601 | |||
| 602 | err = regulator_enable(hdmi->pll); | ||
| 603 | if (err < 0) { | ||
| 604 | dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err); | ||
| 605 | return err; | ||
| 606 | } | ||
| 607 | |||
| 608 | /* | ||
| 609 | * This assumes that the display controller will divide its parent | ||
| 610 | * clock by 2 to generate the pixel clock. | ||
| 611 | */ | ||
| 612 | err = tegra_output_setup_clock(output, hdmi->clk, pclk * 2); | ||
| 613 | if (err < 0) { | ||
| 614 | dev_err(hdmi->dev, "failed to setup clock: %d\n", err); | ||
| 615 | return err; | ||
| 616 | } | ||
| 617 | |||
| 618 | err = clk_set_rate(hdmi->clk, pclk); | ||
| 619 | if (err < 0) | ||
| 620 | return err; | ||
| 621 | |||
| 622 | err = clk_enable(hdmi->clk); | ||
| 623 | if (err < 0) { | ||
| 624 | dev_err(hdmi->dev, "failed to enable clock: %d\n", err); | ||
| 625 | return err; | ||
| 626 | } | ||
| 627 | |||
| 628 | tegra_periph_reset_assert(hdmi->clk); | ||
| 629 | usleep_range(1000, 2000); | ||
| 630 | tegra_periph_reset_deassert(hdmi->clk); | ||
| 631 | |||
| 632 | tegra_dc_writel(dc, VSYNC_H_POSITION(1), | ||
| 633 | DC_DISP_DISP_TIMING_OPTIONS); | ||
| 634 | tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888, | ||
| 635 | DC_DISP_DISP_COLOR_CONTROL); | ||
| 636 | |||
| 637 | /* video_preamble uses h_pulse2 */ | ||
| 638 | pulse_start = 1 + h_sync_width + h_back_porch - 10; | ||
| 639 | |||
| 640 | tegra_dc_writel(dc, H_PULSE_2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0); | ||
| 641 | |||
| 642 | value = PULSE_MODE_NORMAL | PULSE_POLARITY_HIGH | PULSE_QUAL_VACTIVE | | ||
| 643 | PULSE_LAST_END_A; | ||
| 644 | tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_CONTROL); | ||
| 645 | |||
| 646 | value = PULSE_START(pulse_start) | PULSE_END(pulse_start + 8); | ||
| 647 | tegra_dc_writel(dc, value, DC_DISP_H_PULSE2_POSITION_A); | ||
| 648 | |||
| 649 | value = VSYNC_WINDOW_END(0x210) | VSYNC_WINDOW_START(0x200) | | ||
| 650 | VSYNC_WINDOW_ENABLE; | ||
| 651 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); | ||
| 652 | |||
| 653 | if (dc->pipe) | ||
| 654 | value = HDMI_SRC_DISPLAYB; | ||
| 655 | else | ||
| 656 | value = HDMI_SRC_DISPLAYA; | ||
| 657 | |||
| 658 | if ((mode->hdisplay == 720) && ((mode->vdisplay == 480) || | ||
| 659 | (mode->vdisplay == 576))) | ||
| 660 | tegra_hdmi_writel(hdmi, | ||
| 661 | value | ARM_VIDEO_RANGE_FULL, | ||
| 662 | HDMI_NV_PDISP_INPUT_CONTROL); | ||
| 663 | else | ||
| 664 | tegra_hdmi_writel(hdmi, | ||
| 665 | value | ARM_VIDEO_RANGE_LIMITED, | ||
| 666 | HDMI_NV_PDISP_INPUT_CONTROL); | ||
| 667 | |||
| 668 | div82 = clk_get_rate(hdmi->clk) / 1000000 * 4; | ||
| 669 | value = SOR_REFCLK_DIV_INT(div82 >> 2) | SOR_REFCLK_DIV_FRAC(div82); | ||
| 670 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_REFCLK); | ||
| 671 | |||
| 672 | if (!hdmi->dvi) { | ||
| 673 | err = tegra_hdmi_setup_audio(hdmi, pclk); | ||
| 674 | if (err < 0) | ||
| 675 | hdmi->dvi = true; | ||
| 676 | } | ||
| 677 | |||
| 678 | if (of_device_is_compatible(node, "nvidia,tegra20-hdmi")) { | ||
| 679 | /* | ||
| 680 | * TODO: add ELD support | ||
| 681 | */ | ||
| 682 | } | ||
| 683 | |||
| 684 | rekey = HDMI_REKEY_DEFAULT; | ||
| 685 | value = HDMI_CTRL_REKEY(rekey); | ||
| 686 | value |= HDMI_CTRL_MAX_AC_PACKET((h_sync_width + h_back_porch + | ||
| 687 | h_front_porch - rekey - 18) / 32); | ||
| 688 | |||
| 689 | if (!hdmi->dvi) | ||
| 690 | value |= HDMI_CTRL_ENABLE; | ||
| 691 | |||
| 692 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_HDMI_CTRL); | ||
| 693 | |||
| 694 | if (hdmi->dvi) | ||
| 695 | tegra_hdmi_writel(hdmi, 0x0, | ||
| 696 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 697 | else | ||
| 698 | tegra_hdmi_writel(hdmi, GENERIC_CTRL_AUDIO, | ||
| 699 | HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 700 | |||
| 701 | tegra_hdmi_setup_avi_infoframe(hdmi, mode); | ||
| 702 | tegra_hdmi_setup_audio_infoframe(hdmi); | ||
| 703 | tegra_hdmi_setup_stereo_infoframe(hdmi); | ||
| 704 | |||
| 705 | /* TMDS CONFIG */ | ||
| 706 | if (of_device_is_compatible(node, "nvidia,tegra30-hdmi")) { | ||
| 707 | num_tmds = ARRAY_SIZE(tegra3_tmds_config); | ||
| 708 | tmds = tegra3_tmds_config; | ||
| 709 | } else { | ||
| 710 | num_tmds = ARRAY_SIZE(tegra2_tmds_config); | ||
| 711 | tmds = tegra2_tmds_config; | ||
| 712 | } | ||
| 713 | |||
| 714 | for (i = 0; i < num_tmds; i++) { | ||
| 715 | if (pclk <= tmds[i].pclk) { | ||
| 716 | tegra_hdmi_setup_tmds(hdmi, &tmds[i]); | ||
| 717 | break; | ||
| 718 | } | ||
| 719 | } | ||
| 720 | |||
| 721 | tegra_hdmi_writel(hdmi, | ||
| 722 | SOR_SEQ_CTL_PU_PC(0) | | ||
| 723 | SOR_SEQ_PU_PC_ALT(0) | | ||
| 724 | SOR_SEQ_PD_PC(8) | | ||
| 725 | SOR_SEQ_PD_PC_ALT(8), | ||
| 726 | HDMI_NV_PDISP_SOR_SEQ_CTL); | ||
| 727 | |||
| 728 | value = SOR_SEQ_INST_WAIT_TIME(1) | | ||
| 729 | SOR_SEQ_INST_WAIT_UNITS_VSYNC | | ||
| 730 | SOR_SEQ_INST_HALT | | ||
| 731 | SOR_SEQ_INST_PIN_A_LOW | | ||
| 732 | SOR_SEQ_INST_PIN_B_LOW | | ||
| 733 | SOR_SEQ_INST_DRIVE_PWM_OUT_LO; | ||
| 734 | |||
| 735 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(0)); | ||
| 736 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_SEQ_INST(8)); | ||
| 737 | |||
| 738 | value = 0x1c800; | ||
| 739 | value &= ~SOR_CSTM_ROTCLK(~0); | ||
| 740 | value |= SOR_CSTM_ROTCLK(2); | ||
| 741 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_CSTM); | ||
| 742 | |||
| 743 | tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND); | ||
| 744 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
| 745 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
| 746 | |||
| 747 | /* start SOR */ | ||
| 748 | tegra_hdmi_writel(hdmi, | ||
| 749 | SOR_PWR_NORMAL_STATE_PU | | ||
| 750 | SOR_PWR_NORMAL_START_NORMAL | | ||
| 751 | SOR_PWR_SAFE_STATE_PD | | ||
| 752 | SOR_PWR_SETTING_NEW_TRIGGER, | ||
| 753 | HDMI_NV_PDISP_SOR_PWR); | ||
| 754 | tegra_hdmi_writel(hdmi, | ||
| 755 | SOR_PWR_NORMAL_STATE_PU | | ||
| 756 | SOR_PWR_NORMAL_START_NORMAL | | ||
| 757 | SOR_PWR_SAFE_STATE_PD | | ||
| 758 | SOR_PWR_SETTING_NEW_DONE, | ||
| 759 | HDMI_NV_PDISP_SOR_PWR); | ||
| 760 | |||
| 761 | do { | ||
| 762 | BUG_ON(--retries < 0); | ||
| 763 | value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR); | ||
| 764 | } while (value & SOR_PWR_SETTING_NEW_PENDING); | ||
| 765 | |||
| 766 | value = SOR_STATE_ASY_CRCMODE_COMPLETE | | ||
| 767 | SOR_STATE_ASY_OWNER_HEAD0 | | ||
| 768 | SOR_STATE_ASY_SUBOWNER_BOTH | | ||
| 769 | SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A | | ||
| 770 | SOR_STATE_ASY_DEPOL_POS; | ||
| 771 | |||
| 772 | /* setup sync polarities */ | ||
| 773 | if (mode->flags & DRM_MODE_FLAG_PHSYNC) | ||
| 774 | value |= SOR_STATE_ASY_HSYNCPOL_POS; | ||
| 775 | |||
| 776 | if (mode->flags & DRM_MODE_FLAG_NHSYNC) | ||
| 777 | value |= SOR_STATE_ASY_HSYNCPOL_NEG; | ||
| 778 | |||
| 779 | if (mode->flags & DRM_MODE_FLAG_PVSYNC) | ||
| 780 | value |= SOR_STATE_ASY_VSYNCPOL_POS; | ||
| 781 | |||
| 782 | if (mode->flags & DRM_MODE_FLAG_NVSYNC) | ||
| 783 | value |= SOR_STATE_ASY_VSYNCPOL_NEG; | ||
| 784 | |||
| 785 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_STATE2); | ||
| 786 | |||
| 787 | value = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL; | ||
| 788 | tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_STATE1); | ||
| 789 | |||
| 790 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); | ||
| 791 | tegra_hdmi_writel(hdmi, SOR_STATE_UPDATE, HDMI_NV_PDISP_SOR_STATE0); | ||
| 792 | tegra_hdmi_writel(hdmi, value | SOR_STATE_ATTACHED, | ||
| 793 | HDMI_NV_PDISP_SOR_STATE1); | ||
| 794 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0); | ||
| 795 | |||
| 796 | tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS); | ||
| 797 | |||
| 798 | value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | | ||
| 799 | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE; | ||
| 800 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL); | ||
| 801 | |||
| 802 | value = DISP_CTRL_MODE_C_DISPLAY; | ||
| 803 | tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND); | ||
| 804 | |||
| 805 | tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); | ||
| 806 | tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); | ||
| 807 | |||
| 808 | /* TODO: add HDCP support */ | ||
| 809 | |||
| 810 | return 0; | ||
| 811 | } | ||
| 812 | |||
| 813 | static int tegra_output_hdmi_disable(struct tegra_output *output) | ||
| 814 | { | ||
| 815 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
| 816 | |||
| 817 | tegra_periph_reset_assert(hdmi->clk); | ||
| 818 | clk_disable(hdmi->clk); | ||
| 819 | regulator_disable(hdmi->pll); | ||
| 820 | regulator_disable(hdmi->vdd); | ||
| 821 | |||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | |||
| 825 | static int tegra_output_hdmi_setup_clock(struct tegra_output *output, | ||
| 826 | struct clk *clk, unsigned long pclk) | ||
| 827 | { | ||
| 828 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
| 829 | struct clk *base; | ||
| 830 | int err; | ||
| 831 | |||
| 832 | err = clk_set_parent(clk, hdmi->clk_parent); | ||
| 833 | if (err < 0) { | ||
| 834 | dev_err(output->dev, "failed to set parent: %d\n", err); | ||
| 835 | return err; | ||
| 836 | } | ||
| 837 | |||
| 838 | base = clk_get_parent(hdmi->clk_parent); | ||
| 839 | |||
| 840 | /* | ||
| 841 | * This assumes that the parent clock is pll_d_out0 or pll_d2_out | ||
| 842 | * respectively, each of which divides the base pll_d by 2. | ||
| 843 | */ | ||
| 844 | err = clk_set_rate(base, pclk * 2); | ||
| 845 | if (err < 0) | ||
| 846 | dev_err(output->dev, | ||
| 847 | "failed to set base clock rate to %lu Hz\n", | ||
| 848 | pclk * 2); | ||
| 849 | |||
| 850 | return 0; | ||
| 851 | } | ||
| 852 | |||
| 853 | static int tegra_output_hdmi_check_mode(struct tegra_output *output, | ||
| 854 | struct drm_display_mode *mode, | ||
| 855 | enum drm_mode_status *status) | ||
| 856 | { | ||
| 857 | struct tegra_hdmi *hdmi = to_hdmi(output); | ||
| 858 | unsigned long pclk = mode->clock * 1000; | ||
| 859 | struct clk *parent; | ||
| 860 | long err; | ||
| 861 | |||
| 862 | parent = clk_get_parent(hdmi->clk_parent); | ||
| 863 | |||
| 864 | err = clk_round_rate(parent, pclk * 4); | ||
| 865 | if (err < 0) | ||
| 866 | *status = MODE_NOCLOCK; | ||
| 867 | else | ||
| 868 | *status = MODE_OK; | ||
| 869 | |||
| 870 | return 0; | ||
| 871 | } | ||
| 872 | |||
| 873 | static const struct tegra_output_ops hdmi_ops = { | ||
| 874 | .enable = tegra_output_hdmi_enable, | ||
| 875 | .disable = tegra_output_hdmi_disable, | ||
| 876 | .setup_clock = tegra_output_hdmi_setup_clock, | ||
| 877 | .check_mode = tegra_output_hdmi_check_mode, | ||
| 878 | }; | ||
| 879 | |||
| 880 | static int tegra_hdmi_show_regs(struct seq_file *s, void *data) | ||
| 881 | { | ||
| 882 | struct drm_info_node *node = s->private; | ||
| 883 | struct tegra_hdmi *hdmi = node->info_ent->data; | ||
| 884 | int err; | ||
| 885 | |||
| 886 | err = clk_enable(hdmi->clk); | ||
| 887 | if (err) | ||
| 888 | return err; | ||
| 889 | |||
| 890 | #define DUMP_REG(name) \ | ||
| 891 | seq_printf(s, "%-56s %#05x %08lx\n", #name, name, \ | ||
| 892 | tegra_hdmi_readl(hdmi, name)) | ||
| 893 | |||
| 894 | DUMP_REG(HDMI_CTXSW); | ||
| 895 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE0); | ||
| 896 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE1); | ||
| 897 | DUMP_REG(HDMI_NV_PDISP_SOR_STATE2); | ||
| 898 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_MSB); | ||
| 899 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_LSB); | ||
| 900 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_MSB); | ||
| 901 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_LSB); | ||
| 902 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_MSB); | ||
| 903 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_LSB); | ||
| 904 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_MSB); | ||
| 905 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_LSB); | ||
| 906 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_MSB); | ||
| 907 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_LSB); | ||
| 908 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_MSB); | ||
| 909 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_LSB); | ||
| 910 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CTRL); | ||
| 911 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CMODE); | ||
| 912 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB); | ||
| 913 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB); | ||
| 914 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB); | ||
| 915 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2); | ||
| 916 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1); | ||
| 917 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_RI); | ||
| 918 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_MSB); | ||
| 919 | DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_LSB); | ||
| 920 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU0); | ||
| 921 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0); | ||
| 922 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU1); | ||
| 923 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU2); | ||
| 924 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL); | ||
| 925 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS); | ||
| 926 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER); | ||
| 927 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW); | ||
| 928 | DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH); | ||
| 929 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL); | ||
| 930 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS); | ||
| 931 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER); | ||
| 932 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW); | ||
| 933 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH); | ||
| 934 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW); | ||
| 935 | DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH); | ||
| 936 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_CTRL); | ||
| 937 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_STATUS); | ||
| 938 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_HEADER); | ||
| 939 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW); | ||
| 940 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH); | ||
| 941 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW); | ||
| 942 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH); | ||
| 943 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW); | ||
| 944 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH); | ||
| 945 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW); | ||
| 946 | DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH); | ||
| 947 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_CTRL); | ||
| 948 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW); | ||
| 949 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH); | ||
| 950 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW); | ||
| 951 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH); | ||
| 952 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW); | ||
| 953 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH); | ||
| 954 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW); | ||
| 955 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH); | ||
| 956 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW); | ||
| 957 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH); | ||
| 958 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW); | ||
| 959 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH); | ||
| 960 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW); | ||
| 961 | DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH); | ||
| 962 | DUMP_REG(HDMI_NV_PDISP_HDMI_CTRL); | ||
| 963 | DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT); | ||
| 964 | DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_WINDOW); | ||
| 965 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_CTRL); | ||
| 966 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_STATUS); | ||
| 967 | DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_SUBPACK); | ||
| 968 | DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1); | ||
| 969 | DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2); | ||
| 970 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU0); | ||
| 971 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1); | ||
| 972 | DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1_RDATA); | ||
| 973 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPARE); | ||
| 974 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1); | ||
| 975 | DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2); | ||
| 976 | DUMP_REG(HDMI_NV_PDISP_HDMI_HDCPRIF_ROM_CTRL); | ||
| 977 | DUMP_REG(HDMI_NV_PDISP_SOR_CAP); | ||
| 978 | DUMP_REG(HDMI_NV_PDISP_SOR_PWR); | ||
| 979 | DUMP_REG(HDMI_NV_PDISP_SOR_TEST); | ||
| 980 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL0); | ||
| 981 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL1); | ||
| 982 | DUMP_REG(HDMI_NV_PDISP_SOR_PLL2); | ||
| 983 | DUMP_REG(HDMI_NV_PDISP_SOR_CSTM); | ||
| 984 | DUMP_REG(HDMI_NV_PDISP_SOR_LVDS); | ||
| 985 | DUMP_REG(HDMI_NV_PDISP_SOR_CRCA); | ||
| 986 | DUMP_REG(HDMI_NV_PDISP_SOR_CRCB); | ||
| 987 | DUMP_REG(HDMI_NV_PDISP_SOR_BLANK); | ||
| 988 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_CTL); | ||
| 989 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(0)); | ||
| 990 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(1)); | ||
| 991 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(2)); | ||
| 992 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(3)); | ||
| 993 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(4)); | ||
| 994 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(5)); | ||
| 995 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(6)); | ||
| 996 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(7)); | ||
| 997 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(8)); | ||
| 998 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(9)); | ||
| 999 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(10)); | ||
| 1000 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(11)); | ||
| 1001 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(12)); | ||
| 1002 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(13)); | ||
| 1003 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(14)); | ||
| 1004 | DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST(15)); | ||
| 1005 | DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA0); | ||
| 1006 | DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA1); | ||
| 1007 | DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA0); | ||
| 1008 | DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA1); | ||
| 1009 | DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA0); | ||
| 1010 | DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA1); | ||
| 1011 | DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA0); | ||
| 1012 | DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA1); | ||
| 1013 | DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA0); | ||
| 1014 | DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA1); | ||
| 1015 | DUMP_REG(HDMI_NV_PDISP_SOR_TRIG); | ||
| 1016 | DUMP_REG(HDMI_NV_PDISP_SOR_MSCHECK); | ||
| 1017 | DUMP_REG(HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT); | ||
| 1018 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG0); | ||
| 1019 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG1); | ||
| 1020 | DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG2); | ||
| 1021 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(0)); | ||
| 1022 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(1)); | ||
| 1023 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(2)); | ||
| 1024 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(3)); | ||
| 1025 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(4)); | ||
| 1026 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(5)); | ||
| 1027 | DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(6)); | ||
| 1028 | DUMP_REG(HDMI_NV_PDISP_AUDIO_PULSE_WIDTH); | ||
| 1029 | DUMP_REG(HDMI_NV_PDISP_AUDIO_THRESHOLD); | ||
| 1030 | DUMP_REG(HDMI_NV_PDISP_AUDIO_CNTRL0); | ||
| 1031 | DUMP_REG(HDMI_NV_PDISP_AUDIO_N); | ||
| 1032 | DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_TIMING); | ||
| 1033 | DUMP_REG(HDMI_NV_PDISP_SOR_REFCLK); | ||
| 1034 | DUMP_REG(HDMI_NV_PDISP_CRC_CONTROL); | ||
| 1035 | DUMP_REG(HDMI_NV_PDISP_INPUT_CONTROL); | ||
| 1036 | DUMP_REG(HDMI_NV_PDISP_SCRATCH); | ||
| 1037 | DUMP_REG(HDMI_NV_PDISP_PE_CURRENT); | ||
| 1038 | DUMP_REG(HDMI_NV_PDISP_KEY_CTRL); | ||
| 1039 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG0); | ||
| 1040 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG1); | ||
| 1041 | DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG2); | ||
| 1042 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_0); | ||
| 1043 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_1); | ||
| 1044 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_2); | ||
| 1045 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_3); | ||
| 1046 | DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG); | ||
| 1047 | DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX); | ||
| 1048 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_CNTRL0); | ||
| 1049 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR); | ||
| 1050 | DUMP_REG(HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE); | ||
| 1051 | |||
| 1052 | #undef DUMP_REG | ||
| 1053 | |||
| 1054 | clk_disable(hdmi->clk); | ||
| 1055 | |||
| 1056 | return 0; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | static struct drm_info_list debugfs_files[] = { | ||
| 1060 | { "regs", tegra_hdmi_show_regs, 0, NULL }, | ||
| 1061 | }; | ||
| 1062 | |||
| 1063 | static int tegra_hdmi_debugfs_init(struct tegra_hdmi *hdmi, | ||
| 1064 | struct drm_minor *minor) | ||
| 1065 | { | ||
| 1066 | unsigned int i; | ||
| 1067 | int err; | ||
| 1068 | |||
| 1069 | hdmi->debugfs = debugfs_create_dir("hdmi", minor->debugfs_root); | ||
| 1070 | if (!hdmi->debugfs) | ||
| 1071 | return -ENOMEM; | ||
| 1072 | |||
| 1073 | hdmi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files), | ||
| 1074 | GFP_KERNEL); | ||
| 1075 | if (!hdmi->debugfs_files) { | ||
| 1076 | err = -ENOMEM; | ||
| 1077 | goto remove; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) | ||
| 1081 | hdmi->debugfs_files[i].data = hdmi; | ||
| 1082 | |||
| 1083 | err = drm_debugfs_create_files(hdmi->debugfs_files, | ||
| 1084 | ARRAY_SIZE(debugfs_files), | ||
| 1085 | hdmi->debugfs, minor); | ||
| 1086 | if (err < 0) | ||
| 1087 | goto free; | ||
| 1088 | |||
| 1089 | hdmi->minor = minor; | ||
| 1090 | |||
| 1091 | return 0; | ||
| 1092 | |||
| 1093 | free: | ||
| 1094 | kfree(hdmi->debugfs_files); | ||
| 1095 | hdmi->debugfs_files = NULL; | ||
| 1096 | remove: | ||
| 1097 | debugfs_remove(hdmi->debugfs); | ||
| 1098 | hdmi->debugfs = NULL; | ||
| 1099 | |||
| 1100 | return err; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi) | ||
| 1104 | { | ||
| 1105 | drm_debugfs_remove_files(hdmi->debugfs_files, ARRAY_SIZE(debugfs_files), | ||
| 1106 | hdmi->minor); | ||
| 1107 | hdmi->minor = NULL; | ||
| 1108 | |||
| 1109 | kfree(hdmi->debugfs_files); | ||
| 1110 | hdmi->debugfs_files = NULL; | ||
| 1111 | |||
| 1112 | debugfs_remove(hdmi->debugfs); | ||
| 1113 | hdmi->debugfs = NULL; | ||
| 1114 | |||
| 1115 | return 0; | ||
| 1116 | } | ||
| 1117 | |||
| 1118 | static int tegra_hdmi_init(struct host1x_client *client) | ||
| 1119 | { | ||
| 1120 | struct tegra_drm *tegra = dev_get_drvdata(client->parent); | ||
| 1121 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | ||
| 1122 | int err; | ||
| 1123 | |||
| 1124 | hdmi->output.type = TEGRA_OUTPUT_HDMI; | ||
| 1125 | hdmi->output.dev = client->dev; | ||
| 1126 | hdmi->output.ops = &hdmi_ops; | ||
| 1127 | |||
| 1128 | err = tegra_output_init(tegra->drm, &hdmi->output); | ||
| 1129 | if (err < 0) { | ||
| 1130 | dev_err(client->dev, "output setup failed: %d\n", err); | ||
| 1131 | return err; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
| 1135 | err = tegra_hdmi_debugfs_init(hdmi, tegra->drm->primary); | ||
| 1136 | if (err < 0) | ||
| 1137 | dev_err(client->dev, "debugfs setup failed: %d\n", err); | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | return 0; | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | static int tegra_hdmi_exit(struct host1x_client *client) | ||
| 1144 | { | ||
| 1145 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | ||
| 1146 | int err; | ||
| 1147 | |||
| 1148 | if (IS_ENABLED(CONFIG_DEBUG_FS)) { | ||
| 1149 | err = tegra_hdmi_debugfs_exit(hdmi); | ||
| 1150 | if (err < 0) | ||
| 1151 | dev_err(client->dev, "debugfs cleanup failed: %d\n", | ||
| 1152 | err); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | err = tegra_output_disable(&hdmi->output); | ||
| 1156 | if (err < 0) { | ||
| 1157 | dev_err(client->dev, "output failed to disable: %d\n", err); | ||
| 1158 | return err; | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | err = tegra_output_exit(&hdmi->output); | ||
| 1162 | if (err < 0) { | ||
| 1163 | dev_err(client->dev, "output cleanup failed: %d\n", err); | ||
| 1164 | return err; | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | return 0; | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | static const struct host1x_client_ops hdmi_client_ops = { | ||
| 1171 | .init = tegra_hdmi_init, | ||
| 1172 | .exit = tegra_hdmi_exit, | ||
| 1173 | }; | ||
| 1174 | |||
| 1175 | static int tegra_hdmi_probe(struct platform_device *pdev) | ||
| 1176 | { | ||
| 1177 | struct tegra_hdmi *hdmi; | ||
| 1178 | struct resource *regs; | ||
| 1179 | int err; | ||
| 1180 | |||
| 1181 | hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL); | ||
| 1182 | if (!hdmi) | ||
| 1183 | return -ENOMEM; | ||
| 1184 | |||
| 1185 | hdmi->dev = &pdev->dev; | ||
| 1186 | hdmi->audio_source = AUTO; | ||
| 1187 | hdmi->audio_freq = 44100; | ||
| 1188 | hdmi->stereo = false; | ||
| 1189 | hdmi->dvi = false; | ||
| 1190 | |||
| 1191 | hdmi->clk = devm_clk_get(&pdev->dev, NULL); | ||
| 1192 | if (IS_ERR(hdmi->clk)) { | ||
| 1193 | dev_err(&pdev->dev, "failed to get clock\n"); | ||
| 1194 | return PTR_ERR(hdmi->clk); | ||
| 1195 | } | ||
| 1196 | |||
| 1197 | err = clk_prepare(hdmi->clk); | ||
| 1198 | if (err < 0) | ||
| 1199 | return err; | ||
| 1200 | |||
| 1201 | hdmi->clk_parent = devm_clk_get(&pdev->dev, "parent"); | ||
| 1202 | if (IS_ERR(hdmi->clk_parent)) | ||
| 1203 | return PTR_ERR(hdmi->clk_parent); | ||
| 1204 | |||
| 1205 | err = clk_prepare(hdmi->clk_parent); | ||
| 1206 | if (err < 0) | ||
| 1207 | return err; | ||
| 1208 | |||
| 1209 | err = clk_set_parent(hdmi->clk, hdmi->clk_parent); | ||
| 1210 | if (err < 0) { | ||
| 1211 | dev_err(&pdev->dev, "failed to setup clocks: %d\n", err); | ||
| 1212 | return err; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | hdmi->vdd = devm_regulator_get(&pdev->dev, "vdd"); | ||
| 1216 | if (IS_ERR(hdmi->vdd)) { | ||
| 1217 | dev_err(&pdev->dev, "failed to get VDD regulator\n"); | ||
| 1218 | return PTR_ERR(hdmi->vdd); | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | hdmi->pll = devm_regulator_get(&pdev->dev, "pll"); | ||
| 1222 | if (IS_ERR(hdmi->pll)) { | ||
| 1223 | dev_err(&pdev->dev, "failed to get PLL regulator\n"); | ||
| 1224 | return PTR_ERR(hdmi->pll); | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | hdmi->output.dev = &pdev->dev; | ||
| 1228 | |||
| 1229 | err = tegra_output_parse_dt(&hdmi->output); | ||
| 1230 | if (err < 0) | ||
| 1231 | return err; | ||
| 1232 | |||
| 1233 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 1234 | if (!regs) | ||
| 1235 | return -ENXIO; | ||
| 1236 | |||
| 1237 | hdmi->regs = devm_ioremap_resource(&pdev->dev, regs); | ||
| 1238 | if (IS_ERR(hdmi->regs)) | ||
| 1239 | return PTR_ERR(hdmi->regs); | ||
| 1240 | |||
| 1241 | err = platform_get_irq(pdev, 0); | ||
| 1242 | if (err < 0) | ||
| 1243 | return err; | ||
| 1244 | |||
| 1245 | hdmi->irq = err; | ||
| 1246 | |||
| 1247 | INIT_LIST_HEAD(&hdmi->client.list); | ||
| 1248 | hdmi->client.ops = &hdmi_client_ops; | ||
| 1249 | hdmi->client.dev = &pdev->dev; | ||
| 1250 | |||
| 1251 | err = host1x_client_register(&hdmi->client); | ||
| 1252 | if (err < 0) { | ||
| 1253 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | ||
| 1254 | err); | ||
| 1255 | return err; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | platform_set_drvdata(pdev, hdmi); | ||
| 1259 | |||
| 1260 | return 0; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | static int tegra_hdmi_remove(struct platform_device *pdev) | ||
| 1264 | { | ||
| 1265 | struct tegra_hdmi *hdmi = platform_get_drvdata(pdev); | ||
| 1266 | int err; | ||
| 1267 | |||
| 1268 | err = host1x_client_unregister(&hdmi->client); | ||
| 1269 | if (err < 0) { | ||
| 1270 | dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", | ||
| 1271 | err); | ||
| 1272 | return err; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | clk_unprepare(hdmi->clk_parent); | ||
| 1276 | clk_unprepare(hdmi->clk); | ||
| 1277 | |||
| 1278 | return 0; | ||
| 1279 | } | ||
| 1280 | |||
| 1281 | static struct of_device_id tegra_hdmi_of_match[] = { | ||
| 1282 | { .compatible = "nvidia,tegra30-hdmi", }, | ||
| 1283 | { .compatible = "nvidia,tegra20-hdmi", }, | ||
| 1284 | { }, | ||
| 1285 | }; | ||
| 1286 | |||
| 1287 | struct platform_driver tegra_hdmi_driver = { | ||
| 1288 | .driver = { | ||
| 1289 | .name = "tegra-hdmi", | ||
| 1290 | .owner = THIS_MODULE, | ||
| 1291 | .of_match_table = tegra_hdmi_of_match, | ||
| 1292 | }, | ||
| 1293 | .probe = tegra_hdmi_probe, | ||
| 1294 | .remove = tegra_hdmi_remove, | ||
| 1295 | }; | ||
diff --git a/drivers/gpu/host1x/drm/hdmi.h b/drivers/gpu/host1x/drm/hdmi.h deleted file mode 100644 index 52ac36e08ccb..000000000000 --- a/drivers/gpu/host1x/drm/hdmi.h +++ /dev/null | |||
| @@ -1,386 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef TEGRA_HDMI_H | ||
| 11 | #define TEGRA_HDMI_H 1 | ||
| 12 | |||
| 13 | /* register definitions */ | ||
| 14 | #define HDMI_CTXSW 0x00 | ||
| 15 | |||
| 16 | #define HDMI_NV_PDISP_SOR_STATE0 0x01 | ||
| 17 | #define SOR_STATE_UPDATE (1 << 0) | ||
| 18 | |||
| 19 | #define HDMI_NV_PDISP_SOR_STATE1 0x02 | ||
| 20 | #define SOR_STATE_ASY_HEAD_OPMODE_AWAKE (2 << 0) | ||
| 21 | #define SOR_STATE_ASY_ORMODE_NORMAL (1 << 2) | ||
| 22 | #define SOR_STATE_ATTACHED (1 << 3) | ||
| 23 | |||
| 24 | #define HDMI_NV_PDISP_SOR_STATE2 0x03 | ||
| 25 | #define SOR_STATE_ASY_OWNER_NONE (0 << 0) | ||
| 26 | #define SOR_STATE_ASY_OWNER_HEAD0 (1 << 0) | ||
| 27 | #define SOR_STATE_ASY_SUBOWNER_NONE (0 << 4) | ||
| 28 | #define SOR_STATE_ASY_SUBOWNER_SUBHEAD0 (1 << 4) | ||
| 29 | #define SOR_STATE_ASY_SUBOWNER_SUBHEAD1 (2 << 4) | ||
| 30 | #define SOR_STATE_ASY_SUBOWNER_BOTH (3 << 4) | ||
| 31 | #define SOR_STATE_ASY_CRCMODE_ACTIVE (0 << 6) | ||
| 32 | #define SOR_STATE_ASY_CRCMODE_COMPLETE (1 << 6) | ||
| 33 | #define SOR_STATE_ASY_CRCMODE_NON_ACTIVE (2 << 6) | ||
| 34 | #define SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A (1 << 8) | ||
| 35 | #define SOR_STATE_ASY_PROTOCOL_CUSTOM (15 << 8) | ||
| 36 | #define SOR_STATE_ASY_HSYNCPOL_POS (0 << 12) | ||
| 37 | #define SOR_STATE_ASY_HSYNCPOL_NEG (1 << 12) | ||
| 38 | #define SOR_STATE_ASY_VSYNCPOL_POS (0 << 13) | ||
| 39 | #define SOR_STATE_ASY_VSYNCPOL_NEG (1 << 13) | ||
| 40 | #define SOR_STATE_ASY_DEPOL_POS (0 << 14) | ||
| 41 | #define SOR_STATE_ASY_DEPOL_NEG (1 << 14) | ||
| 42 | |||
| 43 | #define HDMI_NV_PDISP_RG_HDCP_AN_MSB 0x04 | ||
| 44 | #define HDMI_NV_PDISP_RG_HDCP_AN_LSB 0x05 | ||
| 45 | #define HDMI_NV_PDISP_RG_HDCP_CN_MSB 0x06 | ||
| 46 | #define HDMI_NV_PDISP_RG_HDCP_CN_LSB 0x07 | ||
| 47 | #define HDMI_NV_PDISP_RG_HDCP_AKSV_MSB 0x08 | ||
| 48 | #define HDMI_NV_PDISP_RG_HDCP_AKSV_LSB 0x09 | ||
| 49 | #define HDMI_NV_PDISP_RG_HDCP_BKSV_MSB 0x0a | ||
| 50 | #define HDMI_NV_PDISP_RG_HDCP_BKSV_LSB 0x0b | ||
| 51 | #define HDMI_NV_PDISP_RG_HDCP_CKSV_MSB 0x0c | ||
| 52 | #define HDMI_NV_PDISP_RG_HDCP_CKSV_LSB 0x0d | ||
| 53 | #define HDMI_NV_PDISP_RG_HDCP_DKSV_MSB 0x0e | ||
| 54 | #define HDMI_NV_PDISP_RG_HDCP_DKSV_LSB 0x0f | ||
| 55 | #define HDMI_NV_PDISP_RG_HDCP_CTRL 0x10 | ||
| 56 | #define HDMI_NV_PDISP_RG_HDCP_CMODE 0x11 | ||
| 57 | #define HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB 0x12 | ||
| 58 | #define HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB 0x13 | ||
| 59 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB 0x14 | ||
| 60 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2 0x15 | ||
| 61 | #define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1 0x16 | ||
| 62 | #define HDMI_NV_PDISP_RG_HDCP_RI 0x17 | ||
| 63 | #define HDMI_NV_PDISP_RG_HDCP_CS_MSB 0x18 | ||
| 64 | #define HDMI_NV_PDISP_RG_HDCP_CS_LSB 0x19 | ||
| 65 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU0 0x1a | ||
| 66 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0 0x1b | ||
| 67 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU1 0x1c | ||
| 68 | #define HDMI_NV_PDISP_HDMI_AUDIO_EMU2 0x1d | ||
| 69 | |||
| 70 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL 0x1e | ||
| 71 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS 0x1f | ||
| 72 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER 0x20 | ||
| 73 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW 0x21 | ||
| 74 | #define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH 0x22 | ||
| 75 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL 0x23 | ||
| 76 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS 0x24 | ||
| 77 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER 0x25 | ||
| 78 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW 0x26 | ||
| 79 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH 0x27 | ||
| 80 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW 0x28 | ||
| 81 | #define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH 0x29 | ||
| 82 | |||
| 83 | #define INFOFRAME_CTRL_ENABLE (1 << 0) | ||
| 84 | |||
| 85 | #define INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0) | ||
| 86 | #define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8) | ||
| 87 | #define INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16) | ||
| 88 | |||
| 89 | #define HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x2a | ||
| 90 | #define GENERIC_CTRL_ENABLE (1 << 0) | ||
| 91 | #define GENERIC_CTRL_OTHER (1 << 4) | ||
| 92 | #define GENERIC_CTRL_SINGLE (1 << 8) | ||
| 93 | #define GENERIC_CTRL_HBLANK (1 << 12) | ||
| 94 | #define GENERIC_CTRL_AUDIO (1 << 16) | ||
| 95 | |||
| 96 | #define HDMI_NV_PDISP_HDMI_GENERIC_STATUS 0x2b | ||
| 97 | #define HDMI_NV_PDISP_HDMI_GENERIC_HEADER 0x2c | ||
| 98 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW 0x2d | ||
| 99 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH 0x2e | ||
| 100 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW 0x2f | ||
| 101 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH 0x30 | ||
| 102 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW 0x31 | ||
| 103 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH 0x32 | ||
| 104 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW 0x33 | ||
| 105 | #define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH 0x34 | ||
| 106 | |||
| 107 | #define HDMI_NV_PDISP_HDMI_ACR_CTRL 0x35 | ||
| 108 | #define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW 0x36 | ||
| 109 | #define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH 0x37 | ||
| 110 | #define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW 0x38 | ||
| 111 | #define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH 0x39 | ||
| 112 | #define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW 0x3a | ||
| 113 | #define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH 0x3b | ||
| 114 | #define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW 0x3c | ||
| 115 | #define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH 0x3d | ||
| 116 | #define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW 0x3e | ||
| 117 | #define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH 0x3f | ||
| 118 | #define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW 0x40 | ||
| 119 | #define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH 0x41 | ||
| 120 | #define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW 0x42 | ||
| 121 | #define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH 0x43 | ||
| 122 | |||
| 123 | #define ACR_SUBPACK_CTS(x) (((x) & 0xffffff) << 8) | ||
| 124 | #define ACR_SUBPACK_N(x) (((x) & 0xffffff) << 0) | ||
| 125 | #define ACR_ENABLE (1 << 31) | ||
| 126 | |||
| 127 | #define HDMI_NV_PDISP_HDMI_CTRL 0x44 | ||
| 128 | #define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0) | ||
| 129 | #define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16) | ||
| 130 | #define HDMI_CTRL_ENABLE (1 << 30) | ||
| 131 | |||
| 132 | #define HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT 0x45 | ||
| 133 | #define HDMI_NV_PDISP_HDMI_VSYNC_WINDOW 0x46 | ||
| 134 | #define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0) | ||
| 135 | #define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16) | ||
| 136 | #define VSYNC_WINDOW_ENABLE (1 << 31) | ||
| 137 | |||
| 138 | #define HDMI_NV_PDISP_HDMI_GCP_CTRL 0x47 | ||
| 139 | #define HDMI_NV_PDISP_HDMI_GCP_STATUS 0x48 | ||
| 140 | #define HDMI_NV_PDISP_HDMI_GCP_SUBPACK 0x49 | ||
| 141 | #define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1 0x4a | ||
| 142 | #define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2 0x4b | ||
| 143 | #define HDMI_NV_PDISP_HDMI_EMU0 0x4c | ||
| 144 | #define HDMI_NV_PDISP_HDMI_EMU1 0x4d | ||
| 145 | #define HDMI_NV_PDISP_HDMI_EMU1_RDATA 0x4e | ||
| 146 | |||
| 147 | #define HDMI_NV_PDISP_HDMI_SPARE 0x4f | ||
| 148 | #define SPARE_HW_CTS (1 << 0) | ||
| 149 | #define SPARE_FORCE_SW_CTS (1 << 1) | ||
| 150 | #define SPARE_CTS_RESET_VAL(x) (((x) & 0x7) << 16) | ||
| 151 | |||
| 152 | #define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1 0x50 | ||
| 153 | #define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2 0x51 | ||
| 154 | #define HDMI_NV_PDISP_HDMI_HDCPRIF_ROM_CTRL 0x53 | ||
| 155 | #define HDMI_NV_PDISP_SOR_CAP 0x54 | ||
| 156 | #define HDMI_NV_PDISP_SOR_PWR 0x55 | ||
| 157 | #define SOR_PWR_NORMAL_STATE_PD (0 << 0) | ||
| 158 | #define SOR_PWR_NORMAL_STATE_PU (1 << 0) | ||
| 159 | #define SOR_PWR_NORMAL_START_NORMAL (0 << 1) | ||
| 160 | #define SOR_PWR_NORMAL_START_ALT (1 << 1) | ||
| 161 | #define SOR_PWR_SAFE_STATE_PD (0 << 16) | ||
| 162 | #define SOR_PWR_SAFE_STATE_PU (1 << 16) | ||
| 163 | #define SOR_PWR_SETTING_NEW_DONE (0 << 31) | ||
| 164 | #define SOR_PWR_SETTING_NEW_PENDING (1 << 31) | ||
| 165 | #define SOR_PWR_SETTING_NEW_TRIGGER (1 << 31) | ||
| 166 | |||
| 167 | #define HDMI_NV_PDISP_SOR_TEST 0x56 | ||
| 168 | #define HDMI_NV_PDISP_SOR_PLL0 0x57 | ||
| 169 | #define SOR_PLL_PWR (1 << 0) | ||
| 170 | #define SOR_PLL_PDBG (1 << 1) | ||
| 171 | #define SOR_PLL_VCAPD (1 << 2) | ||
| 172 | #define SOR_PLL_PDPORT (1 << 3) | ||
| 173 | #define SOR_PLL_RESISTORSEL (1 << 4) | ||
| 174 | #define SOR_PLL_PULLDOWN (1 << 5) | ||
| 175 | #define SOR_PLL_VCOCAP(x) (((x) & 0xf) << 8) | ||
| 176 | #define SOR_PLL_BG_V17_S(x) (((x) & 0xf) << 12) | ||
| 177 | #define SOR_PLL_FILTER(x) (((x) & 0xf) << 16) | ||
| 178 | #define SOR_PLL_ICHPMP(x) (((x) & 0xf) << 24) | ||
| 179 | #define SOR_PLL_TX_REG_LOAD(x) (((x) & 0xf) << 28) | ||
| 180 | |||
| 181 | #define HDMI_NV_PDISP_SOR_PLL1 0x58 | ||
| 182 | #define SOR_PLL_TMDS_TERM_ENABLE (1 << 8) | ||
| 183 | #define SOR_PLL_TMDS_TERMADJ(x) (((x) & 0xf) << 9) | ||
| 184 | #define SOR_PLL_LOADADJ(x) (((x) & 0xf) << 20) | ||
| 185 | #define SOR_PLL_PE_EN (1 << 28) | ||
| 186 | #define SOR_PLL_HALF_FULL_PE (1 << 29) | ||
| 187 | #define SOR_PLL_S_D_PIN_PE (1 << 30) | ||
| 188 | |||
| 189 | #define HDMI_NV_PDISP_SOR_PLL2 0x59 | ||
| 190 | |||
| 191 | #define HDMI_NV_PDISP_SOR_CSTM 0x5a | ||
| 192 | #define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24) | ||
| 193 | |||
| 194 | #define HDMI_NV_PDISP_SOR_LVDS 0x5b | ||
| 195 | #define HDMI_NV_PDISP_SOR_CRCA 0x5c | ||
| 196 | #define HDMI_NV_PDISP_SOR_CRCB 0x5d | ||
| 197 | #define HDMI_NV_PDISP_SOR_BLANK 0x5e | ||
| 198 | #define HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f | ||
| 199 | #define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) << 0) | ||
| 200 | #define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4) | ||
| 201 | #define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8) | ||
| 202 | #define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12) | ||
| 203 | #define SOR_SEQ_PC(x) (((x) & 0xf) << 16) | ||
| 204 | #define SOR_SEQ_STATUS (1 << 28) | ||
| 205 | #define SOR_SEQ_SWITCH (1 << 30) | ||
| 206 | |||
| 207 | #define HDMI_NV_PDISP_SOR_SEQ_INST(x) (0x60 + (x)) | ||
| 208 | |||
| 209 | #define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0) | ||
| 210 | #define SOR_SEQ_INST_WAIT_UNITS_VSYNC (2 << 12) | ||
| 211 | #define SOR_SEQ_INST_HALT (1 << 15) | ||
| 212 | #define SOR_SEQ_INST_PIN_A_LOW (0 << 21) | ||
| 213 | #define SOR_SEQ_INST_PIN_A_HIGH (1 << 21) | ||
| 214 | #define SOR_SEQ_INST_PIN_B_LOW (0 << 22) | ||
| 215 | #define SOR_SEQ_INST_PIN_B_HIGH (1 << 22) | ||
| 216 | #define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23) | ||
| 217 | |||
| 218 | #define HDMI_NV_PDISP_SOR_VCRCA0 0x72 | ||
| 219 | #define HDMI_NV_PDISP_SOR_VCRCA1 0x73 | ||
| 220 | #define HDMI_NV_PDISP_SOR_CCRCA0 0x74 | ||
| 221 | #define HDMI_NV_PDISP_SOR_CCRCA1 0x75 | ||
| 222 | #define HDMI_NV_PDISP_SOR_EDATAA0 0x76 | ||
| 223 | #define HDMI_NV_PDISP_SOR_EDATAA1 0x77 | ||
| 224 | #define HDMI_NV_PDISP_SOR_COUNTA0 0x78 | ||
| 225 | #define HDMI_NV_PDISP_SOR_COUNTA1 0x79 | ||
| 226 | #define HDMI_NV_PDISP_SOR_DEBUGA0 0x7a | ||
| 227 | #define HDMI_NV_PDISP_SOR_DEBUGA1 0x7b | ||
| 228 | #define HDMI_NV_PDISP_SOR_TRIG 0x7c | ||
| 229 | #define HDMI_NV_PDISP_SOR_MSCHECK 0x7d | ||
| 230 | |||
| 231 | #define HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x7e | ||
| 232 | #define DRIVE_CURRENT_LANE0(x) (((x) & 0x3f) << 0) | ||
| 233 | #define DRIVE_CURRENT_LANE1(x) (((x) & 0x3f) << 8) | ||
| 234 | #define DRIVE_CURRENT_LANE2(x) (((x) & 0x3f) << 16) | ||
| 235 | #define DRIVE_CURRENT_LANE3(x) (((x) & 0x3f) << 24) | ||
| 236 | #define DRIVE_CURRENT_FUSE_OVERRIDE (1 << 31) | ||
| 237 | |||
| 238 | #define DRIVE_CURRENT_1_500_mA 0x00 | ||
| 239 | #define DRIVE_CURRENT_1_875_mA 0x01 | ||
| 240 | #define DRIVE_CURRENT_2_250_mA 0x02 | ||
| 241 | #define DRIVE_CURRENT_2_625_mA 0x03 | ||
| 242 | #define DRIVE_CURRENT_3_000_mA 0x04 | ||
| 243 | #define DRIVE_CURRENT_3_375_mA 0x05 | ||
| 244 | #define DRIVE_CURRENT_3_750_mA 0x06 | ||
| 245 | #define DRIVE_CURRENT_4_125_mA 0x07 | ||
| 246 | #define DRIVE_CURRENT_4_500_mA 0x08 | ||
| 247 | #define DRIVE_CURRENT_4_875_mA 0x09 | ||
| 248 | #define DRIVE_CURRENT_5_250_mA 0x0a | ||
| 249 | #define DRIVE_CURRENT_5_625_mA 0x0b | ||
| 250 | #define DRIVE_CURRENT_6_000_mA 0x0c | ||
| 251 | #define DRIVE_CURRENT_6_375_mA 0x0d | ||
| 252 | #define DRIVE_CURRENT_6_750_mA 0x0e | ||
| 253 | #define DRIVE_CURRENT_7_125_mA 0x0f | ||
| 254 | #define DRIVE_CURRENT_7_500_mA 0x10 | ||
| 255 | #define DRIVE_CURRENT_7_875_mA 0x11 | ||
| 256 | #define DRIVE_CURRENT_8_250_mA 0x12 | ||
| 257 | #define DRIVE_CURRENT_8_625_mA 0x13 | ||
| 258 | #define DRIVE_CURRENT_9_000_mA 0x14 | ||
| 259 | #define DRIVE_CURRENT_9_375_mA 0x15 | ||
| 260 | #define DRIVE_CURRENT_9_750_mA 0x16 | ||
| 261 | #define DRIVE_CURRENT_10_125_mA 0x17 | ||
| 262 | #define DRIVE_CURRENT_10_500_mA 0x18 | ||
| 263 | #define DRIVE_CURRENT_10_875_mA 0x19 | ||
| 264 | #define DRIVE_CURRENT_11_250_mA 0x1a | ||
| 265 | #define DRIVE_CURRENT_11_625_mA 0x1b | ||
| 266 | #define DRIVE_CURRENT_12_000_mA 0x1c | ||
| 267 | #define DRIVE_CURRENT_12_375_mA 0x1d | ||
| 268 | #define DRIVE_CURRENT_12_750_mA 0x1e | ||
| 269 | #define DRIVE_CURRENT_13_125_mA 0x1f | ||
| 270 | #define DRIVE_CURRENT_13_500_mA 0x20 | ||
| 271 | #define DRIVE_CURRENT_13_875_mA 0x21 | ||
| 272 | #define DRIVE_CURRENT_14_250_mA 0x22 | ||
| 273 | #define DRIVE_CURRENT_14_625_mA 0x23 | ||
| 274 | #define DRIVE_CURRENT_15_000_mA 0x24 | ||
| 275 | #define DRIVE_CURRENT_15_375_mA 0x25 | ||
| 276 | #define DRIVE_CURRENT_15_750_mA 0x26 | ||
| 277 | #define DRIVE_CURRENT_16_125_mA 0x27 | ||
| 278 | #define DRIVE_CURRENT_16_500_mA 0x28 | ||
| 279 | #define DRIVE_CURRENT_16_875_mA 0x29 | ||
| 280 | #define DRIVE_CURRENT_17_250_mA 0x2a | ||
| 281 | #define DRIVE_CURRENT_17_625_mA 0x2b | ||
| 282 | #define DRIVE_CURRENT_18_000_mA 0x2c | ||
| 283 | #define DRIVE_CURRENT_18_375_mA 0x2d | ||
| 284 | #define DRIVE_CURRENT_18_750_mA 0x2e | ||
| 285 | #define DRIVE_CURRENT_19_125_mA 0x2f | ||
| 286 | #define DRIVE_CURRENT_19_500_mA 0x30 | ||
| 287 | #define DRIVE_CURRENT_19_875_mA 0x31 | ||
| 288 | #define DRIVE_CURRENT_20_250_mA 0x32 | ||
| 289 | #define DRIVE_CURRENT_20_625_mA 0x33 | ||
| 290 | #define DRIVE_CURRENT_21_000_mA 0x34 | ||
| 291 | #define DRIVE_CURRENT_21_375_mA 0x35 | ||
| 292 | #define DRIVE_CURRENT_21_750_mA 0x36 | ||
| 293 | #define DRIVE_CURRENT_22_125_mA 0x37 | ||
| 294 | #define DRIVE_CURRENT_22_500_mA 0x38 | ||
| 295 | #define DRIVE_CURRENT_22_875_mA 0x39 | ||
| 296 | #define DRIVE_CURRENT_23_250_mA 0x3a | ||
| 297 | #define DRIVE_CURRENT_23_625_mA 0x3b | ||
| 298 | #define DRIVE_CURRENT_24_000_mA 0x3c | ||
| 299 | #define DRIVE_CURRENT_24_375_mA 0x3d | ||
| 300 | #define DRIVE_CURRENT_24_750_mA 0x3e | ||
| 301 | |||
| 302 | #define HDMI_NV_PDISP_AUDIO_DEBUG0 0x7f | ||
| 303 | #define HDMI_NV_PDISP_AUDIO_DEBUG1 0x80 | ||
| 304 | #define HDMI_NV_PDISP_AUDIO_DEBUG2 0x81 | ||
| 305 | |||
| 306 | #define HDMI_NV_PDISP_AUDIO_FS(x) (0x82 + (x)) | ||
| 307 | #define AUDIO_FS_LOW(x) (((x) & 0xfff) << 0) | ||
| 308 | #define AUDIO_FS_HIGH(x) (((x) & 0xfff) << 16) | ||
| 309 | |||
| 310 | #define HDMI_NV_PDISP_AUDIO_PULSE_WIDTH 0x89 | ||
| 311 | #define HDMI_NV_PDISP_AUDIO_THRESHOLD 0x8a | ||
| 312 | #define HDMI_NV_PDISP_AUDIO_CNTRL0 0x8b | ||
| 313 | #define AUDIO_CNTRL0_ERROR_TOLERANCE(x) (((x) & 0xff) << 0) | ||
| 314 | #define AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20) | ||
| 315 | #define AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20) | ||
| 316 | #define AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20) | ||
| 317 | #define AUDIO_CNTRL0_FRAMES_PER_BLOCK(x) (((x) & 0xff) << 24) | ||
| 318 | |||
| 319 | #define HDMI_NV_PDISP_AUDIO_N 0x8c | ||
| 320 | #define AUDIO_N_VALUE(x) (((x) & 0xfffff) << 0) | ||
| 321 | #define AUDIO_N_RESETF (1 << 20) | ||
| 322 | #define AUDIO_N_GENERATE_NORMAL (0 << 24) | ||
| 323 | #define AUDIO_N_GENERATE_ALTERNATE (1 << 24) | ||
| 324 | |||
| 325 | #define HDMI_NV_PDISP_HDCPRIF_ROM_TIMING 0x94 | ||
| 326 | #define HDMI_NV_PDISP_SOR_REFCLK 0x95 | ||
| 327 | #define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8) | ||
| 328 | #define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x03) << 6) | ||
| 329 | |||
| 330 | #define HDMI_NV_PDISP_CRC_CONTROL 0x96 | ||
| 331 | #define HDMI_NV_PDISP_INPUT_CONTROL 0x97 | ||
| 332 | #define HDMI_SRC_DISPLAYA (0 << 0) | ||
| 333 | #define HDMI_SRC_DISPLAYB (1 << 0) | ||
| 334 | #define ARM_VIDEO_RANGE_FULL (0 << 1) | ||
| 335 | #define ARM_VIDEO_RANGE_LIMITED (1 << 1) | ||
| 336 | |||
| 337 | #define HDMI_NV_PDISP_SCRATCH 0x98 | ||
| 338 | #define HDMI_NV_PDISP_PE_CURRENT 0x99 | ||
| 339 | #define PE_CURRENT0(x) (((x) & 0xf) << 0) | ||
| 340 | #define PE_CURRENT1(x) (((x) & 0xf) << 8) | ||
| 341 | #define PE_CURRENT2(x) (((x) & 0xf) << 16) | ||
| 342 | #define PE_CURRENT3(x) (((x) & 0xf) << 24) | ||
| 343 | |||
| 344 | #define PE_CURRENT_0_0_mA 0x0 | ||
| 345 | #define PE_CURRENT_0_5_mA 0x1 | ||
| 346 | #define PE_CURRENT_1_0_mA 0x2 | ||
| 347 | #define PE_CURRENT_1_5_mA 0x3 | ||
| 348 | #define PE_CURRENT_2_0_mA 0x4 | ||
| 349 | #define PE_CURRENT_2_5_mA 0x5 | ||
| 350 | #define PE_CURRENT_3_0_mA 0x6 | ||
| 351 | #define PE_CURRENT_3_5_mA 0x7 | ||
| 352 | #define PE_CURRENT_4_0_mA 0x8 | ||
| 353 | #define PE_CURRENT_4_5_mA 0x9 | ||
| 354 | #define PE_CURRENT_5_0_mA 0xa | ||
| 355 | #define PE_CURRENT_5_5_mA 0xb | ||
| 356 | #define PE_CURRENT_6_0_mA 0xc | ||
| 357 | #define PE_CURRENT_6_5_mA 0xd | ||
| 358 | #define PE_CURRENT_7_0_mA 0xe | ||
| 359 | #define PE_CURRENT_7_5_mA 0xf | ||
| 360 | |||
| 361 | #define HDMI_NV_PDISP_KEY_CTRL 0x9a | ||
| 362 | #define HDMI_NV_PDISP_KEY_DEBUG0 0x9b | ||
| 363 | #define HDMI_NV_PDISP_KEY_DEBUG1 0x9c | ||
| 364 | #define HDMI_NV_PDISP_KEY_DEBUG2 0x9d | ||
| 365 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_0 0x9e | ||
| 366 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_1 0x9f | ||
| 367 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_2 0xa0 | ||
| 368 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_3 0xa1 | ||
| 369 | #define HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG 0xa2 | ||
| 370 | #define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3 | ||
| 371 | |||
| 372 | #define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0 0xac | ||
| 373 | #define AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29) | ||
| 374 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR 0xbc | ||
| 375 | #define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE 0xbd | ||
| 376 | |||
| 377 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320 0xbf | ||
| 378 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441 0xc0 | ||
| 379 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882 0xc1 | ||
| 380 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764 0xc2 | ||
| 381 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480 0xc3 | ||
| 382 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960 0xc4 | ||
| 383 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920 0xc5 | ||
| 384 | #define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT 0xc5 | ||
| 385 | |||
| 386 | #endif /* TEGRA_HDMI_H */ | ||
diff --git a/drivers/gpu/host1x/drm/output.c b/drivers/gpu/host1x/drm/output.c deleted file mode 100644 index 8f40fa646cec..000000000000 --- a/drivers/gpu/host1x/drm/output.c +++ /dev/null | |||
| @@ -1,270 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/of_gpio.h> | ||
| 11 | |||
| 12 | #include "drm.h" | ||
| 13 | |||
| 14 | static int tegra_connector_get_modes(struct drm_connector *connector) | ||
| 15 | { | ||
| 16 | struct tegra_output *output = connector_to_output(connector); | ||
| 17 | struct edid *edid = NULL; | ||
| 18 | int err = 0; | ||
| 19 | |||
| 20 | if (output->edid) | ||
| 21 | edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL); | ||
| 22 | else if (output->ddc) | ||
| 23 | edid = drm_get_edid(connector, output->ddc); | ||
| 24 | |||
| 25 | drm_mode_connector_update_edid_property(connector, edid); | ||
| 26 | |||
| 27 | if (edid) { | ||
| 28 | err = drm_add_edid_modes(connector, edid); | ||
| 29 | kfree(edid); | ||
| 30 | } | ||
| 31 | |||
| 32 | return err; | ||
| 33 | } | ||
| 34 | |||
| 35 | static int tegra_connector_mode_valid(struct drm_connector *connector, | ||
| 36 | struct drm_display_mode *mode) | ||
| 37 | { | ||
| 38 | struct tegra_output *output = connector_to_output(connector); | ||
| 39 | enum drm_mode_status status = MODE_OK; | ||
| 40 | int err; | ||
| 41 | |||
| 42 | err = tegra_output_check_mode(output, mode, &status); | ||
| 43 | if (err < 0) | ||
| 44 | return MODE_ERROR; | ||
| 45 | |||
| 46 | return status; | ||
| 47 | } | ||
| 48 | |||
| 49 | static struct drm_encoder * | ||
| 50 | tegra_connector_best_encoder(struct drm_connector *connector) | ||
| 51 | { | ||
| 52 | struct tegra_output *output = connector_to_output(connector); | ||
| 53 | |||
| 54 | return &output->encoder; | ||
| 55 | } | ||
| 56 | |||
| 57 | static const struct drm_connector_helper_funcs connector_helper_funcs = { | ||
| 58 | .get_modes = tegra_connector_get_modes, | ||
| 59 | .mode_valid = tegra_connector_mode_valid, | ||
| 60 | .best_encoder = tegra_connector_best_encoder, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static enum drm_connector_status | ||
| 64 | tegra_connector_detect(struct drm_connector *connector, bool force) | ||
| 65 | { | ||
| 66 | struct tegra_output *output = connector_to_output(connector); | ||
| 67 | enum drm_connector_status status = connector_status_unknown; | ||
| 68 | |||
| 69 | if (gpio_is_valid(output->hpd_gpio)) { | ||
| 70 | if (gpio_get_value(output->hpd_gpio) == 0) | ||
| 71 | status = connector_status_disconnected; | ||
| 72 | else | ||
| 73 | status = connector_status_connected; | ||
| 74 | } else { | ||
| 75 | if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) | ||
| 76 | status = connector_status_connected; | ||
| 77 | } | ||
| 78 | |||
| 79 | return status; | ||
| 80 | } | ||
| 81 | |||
| 82 | static void tegra_connector_destroy(struct drm_connector *connector) | ||
| 83 | { | ||
| 84 | drm_sysfs_connector_remove(connector); | ||
| 85 | drm_connector_cleanup(connector); | ||
| 86 | } | ||
| 87 | |||
| 88 | static const struct drm_connector_funcs connector_funcs = { | ||
| 89 | .dpms = drm_helper_connector_dpms, | ||
| 90 | .detect = tegra_connector_detect, | ||
| 91 | .fill_modes = drm_helper_probe_single_connector_modes, | ||
| 92 | .destroy = tegra_connector_destroy, | ||
| 93 | }; | ||
| 94 | |||
| 95 | static void tegra_encoder_destroy(struct drm_encoder *encoder) | ||
| 96 | { | ||
| 97 | drm_encoder_cleanup(encoder); | ||
| 98 | } | ||
| 99 | |||
| 100 | static const struct drm_encoder_funcs encoder_funcs = { | ||
| 101 | .destroy = tegra_encoder_destroy, | ||
| 102 | }; | ||
| 103 | |||
| 104 | static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
| 105 | { | ||
| 106 | } | ||
| 107 | |||
| 108 | static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder, | ||
| 109 | const struct drm_display_mode *mode, | ||
| 110 | struct drm_display_mode *adjusted) | ||
| 111 | { | ||
| 112 | return true; | ||
| 113 | } | ||
| 114 | |||
| 115 | static void tegra_encoder_prepare(struct drm_encoder *encoder) | ||
| 116 | { | ||
| 117 | } | ||
| 118 | |||
| 119 | static void tegra_encoder_commit(struct drm_encoder *encoder) | ||
| 120 | { | ||
| 121 | } | ||
| 122 | |||
| 123 | static void tegra_encoder_mode_set(struct drm_encoder *encoder, | ||
| 124 | struct drm_display_mode *mode, | ||
| 125 | struct drm_display_mode *adjusted) | ||
| 126 | { | ||
| 127 | struct tegra_output *output = encoder_to_output(encoder); | ||
| 128 | int err; | ||
| 129 | |||
| 130 | err = tegra_output_enable(output); | ||
| 131 | if (err < 0) | ||
| 132 | dev_err(encoder->dev->dev, "tegra_output_enable(): %d\n", err); | ||
| 133 | } | ||
| 134 | |||
| 135 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | ||
| 136 | .dpms = tegra_encoder_dpms, | ||
| 137 | .mode_fixup = tegra_encoder_mode_fixup, | ||
| 138 | .prepare = tegra_encoder_prepare, | ||
| 139 | .commit = tegra_encoder_commit, | ||
| 140 | .mode_set = tegra_encoder_mode_set, | ||
| 141 | }; | ||
| 142 | |||
| 143 | static irqreturn_t hpd_irq(int irq, void *data) | ||
| 144 | { | ||
| 145 | struct tegra_output *output = data; | ||
| 146 | |||
| 147 | drm_helper_hpd_irq_event(output->connector.dev); | ||
| 148 | |||
| 149 | return IRQ_HANDLED; | ||
| 150 | } | ||
| 151 | |||
| 152 | int tegra_output_parse_dt(struct tegra_output *output) | ||
| 153 | { | ||
| 154 | enum of_gpio_flags flags; | ||
| 155 | struct device_node *ddc; | ||
| 156 | size_t size; | ||
| 157 | int err; | ||
| 158 | |||
| 159 | if (!output->of_node) | ||
| 160 | output->of_node = output->dev->of_node; | ||
| 161 | |||
| 162 | output->edid = of_get_property(output->of_node, "nvidia,edid", &size); | ||
| 163 | |||
| 164 | ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0); | ||
| 165 | if (ddc) { | ||
| 166 | output->ddc = of_find_i2c_adapter_by_node(ddc); | ||
| 167 | if (!output->ddc) { | ||
| 168 | err = -EPROBE_DEFER; | ||
| 169 | of_node_put(ddc); | ||
| 170 | return err; | ||
| 171 | } | ||
| 172 | |||
| 173 | of_node_put(ddc); | ||
| 174 | } | ||
| 175 | |||
| 176 | if (!output->edid && !output->ddc) | ||
| 177 | return -ENODEV; | ||
| 178 | |||
| 179 | output->hpd_gpio = of_get_named_gpio_flags(output->of_node, | ||
| 180 | "nvidia,hpd-gpio", 0, | ||
| 181 | &flags); | ||
| 182 | |||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | int tegra_output_init(struct drm_device *drm, struct tegra_output *output) | ||
| 187 | { | ||
| 188 | int connector, encoder, err; | ||
| 189 | |||
| 190 | if (gpio_is_valid(output->hpd_gpio)) { | ||
| 191 | unsigned long flags; | ||
| 192 | |||
| 193 | err = gpio_request_one(output->hpd_gpio, GPIOF_DIR_IN, | ||
| 194 | "HDMI hotplug detect"); | ||
| 195 | if (err < 0) { | ||
| 196 | dev_err(output->dev, "gpio_request_one(): %d\n", err); | ||
| 197 | return err; | ||
| 198 | } | ||
| 199 | |||
| 200 | err = gpio_to_irq(output->hpd_gpio); | ||
| 201 | if (err < 0) { | ||
| 202 | dev_err(output->dev, "gpio_to_irq(): %d\n", err); | ||
| 203 | goto free_hpd; | ||
| 204 | } | ||
| 205 | |||
| 206 | output->hpd_irq = err; | ||
| 207 | |||
| 208 | flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | | ||
| 209 | IRQF_ONESHOT; | ||
| 210 | |||
| 211 | err = request_threaded_irq(output->hpd_irq, NULL, hpd_irq, | ||
| 212 | flags, "hpd", output); | ||
| 213 | if (err < 0) { | ||
| 214 | dev_err(output->dev, "failed to request IRQ#%u: %d\n", | ||
| 215 | output->hpd_irq, err); | ||
| 216 | goto free_hpd; | ||
| 217 | } | ||
| 218 | |||
| 219 | output->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||
| 220 | } | ||
| 221 | |||
| 222 | switch (output->type) { | ||
| 223 | case TEGRA_OUTPUT_RGB: | ||
| 224 | connector = DRM_MODE_CONNECTOR_LVDS; | ||
| 225 | encoder = DRM_MODE_ENCODER_LVDS; | ||
| 226 | break; | ||
| 227 | |||
| 228 | case TEGRA_OUTPUT_HDMI: | ||
| 229 | connector = DRM_MODE_CONNECTOR_HDMIA; | ||
| 230 | encoder = DRM_MODE_ENCODER_TMDS; | ||
| 231 | break; | ||
| 232 | |||
| 233 | default: | ||
| 234 | connector = DRM_MODE_CONNECTOR_Unknown; | ||
| 235 | encoder = DRM_MODE_ENCODER_NONE; | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | |||
| 239 | drm_connector_init(drm, &output->connector, &connector_funcs, | ||
| 240 | connector); | ||
| 241 | drm_connector_helper_add(&output->connector, &connector_helper_funcs); | ||
| 242 | |||
| 243 | drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder); | ||
| 244 | drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs); | ||
| 245 | |||
| 246 | drm_mode_connector_attach_encoder(&output->connector, &output->encoder); | ||
| 247 | drm_sysfs_connector_add(&output->connector); | ||
| 248 | |||
| 249 | output->encoder.possible_crtcs = 0x3; | ||
| 250 | |||
| 251 | return 0; | ||
| 252 | |||
| 253 | free_hpd: | ||
| 254 | gpio_free(output->hpd_gpio); | ||
| 255 | |||
| 256 | return err; | ||
| 257 | } | ||
| 258 | |||
| 259 | int tegra_output_exit(struct tegra_output *output) | ||
| 260 | { | ||
| 261 | if (gpio_is_valid(output->hpd_gpio)) { | ||
| 262 | free_irq(output->hpd_irq, output); | ||
| 263 | gpio_free(output->hpd_gpio); | ||
| 264 | } | ||
| 265 | |||
| 266 | if (output->ddc) | ||
| 267 | put_device(&output->ddc->dev); | ||
| 268 | |||
| 269 | return 0; | ||
| 270 | } | ||
diff --git a/drivers/gpu/host1x/drm/rgb.c b/drivers/gpu/host1x/drm/rgb.c deleted file mode 100644 index e4d28411973d..000000000000 --- a/drivers/gpu/host1x/drm/rgb.c +++ /dev/null | |||
| @@ -1,225 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2012 Avionic Design GmbH | ||
| 3 | * Copyright (C) 2012 NVIDIA CORPORATION. All rights reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License version 2 as | ||
| 7 | * published by the Free Software Foundation. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/clk.h> | ||
| 11 | |||
| 12 | #include "drm.h" | ||
| 13 | #include "dc.h" | ||
| 14 | |||
| 15 | struct tegra_rgb { | ||
| 16 | struct tegra_output output; | ||
| 17 | struct clk *clk_parent; | ||
| 18 | struct clk *clk; | ||
| 19 | }; | ||
| 20 | |||
| 21 | static inline struct tegra_rgb *to_rgb(struct tegra_output *output) | ||
| 22 | { | ||
| 23 | return container_of(output, struct tegra_rgb, output); | ||
| 24 | } | ||
| 25 | |||
| 26 | struct reg_entry { | ||
| 27 | unsigned long offset; | ||
| 28 | unsigned long value; | ||
| 29 | }; | ||
| 30 | |||
| 31 | static const struct reg_entry rgb_enable[] = { | ||
| 32 | { DC_COM_PIN_OUTPUT_ENABLE(0), 0x00000000 }, | ||
| 33 | { DC_COM_PIN_OUTPUT_ENABLE(1), 0x00000000 }, | ||
| 34 | { DC_COM_PIN_OUTPUT_ENABLE(2), 0x00000000 }, | ||
| 35 | { DC_COM_PIN_OUTPUT_ENABLE(3), 0x00000000 }, | ||
| 36 | { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 }, | ||
| 37 | { DC_COM_PIN_OUTPUT_POLARITY(1), 0x01000000 }, | ||
| 38 | { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 }, | ||
| 39 | { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 }, | ||
| 40 | { DC_COM_PIN_OUTPUT_DATA(0), 0x00000000 }, | ||
| 41 | { DC_COM_PIN_OUTPUT_DATA(1), 0x00000000 }, | ||
| 42 | { DC_COM_PIN_OUTPUT_DATA(2), 0x00000000 }, | ||
| 43 | { DC_COM_PIN_OUTPUT_DATA(3), 0x00000000 }, | ||
| 44 | { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 }, | ||
| 45 | { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 }, | ||
| 46 | { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 }, | ||
| 47 | { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 }, | ||
| 48 | { DC_COM_PIN_OUTPUT_SELECT(4), 0x00210222 }, | ||
| 49 | { DC_COM_PIN_OUTPUT_SELECT(5), 0x00002200 }, | ||
| 50 | { DC_COM_PIN_OUTPUT_SELECT(6), 0x00020000 }, | ||
| 51 | }; | ||
| 52 | |||
| 53 | static const struct reg_entry rgb_disable[] = { | ||
| 54 | { DC_COM_PIN_OUTPUT_SELECT(6), 0x00000000 }, | ||
| 55 | { DC_COM_PIN_OUTPUT_SELECT(5), 0x00000000 }, | ||
| 56 | { DC_COM_PIN_OUTPUT_SELECT(4), 0x00000000 }, | ||
| 57 | { DC_COM_PIN_OUTPUT_SELECT(3), 0x00000000 }, | ||
| 58 | { DC_COM_PIN_OUTPUT_SELECT(2), 0x00000000 }, | ||
| 59 | { DC_COM_PIN_OUTPUT_SELECT(1), 0x00000000 }, | ||
| 60 | { DC_COM_PIN_OUTPUT_SELECT(0), 0x00000000 }, | ||
| 61 | { DC_COM_PIN_OUTPUT_DATA(3), 0xaaaaaaaa }, | ||
| 62 | { DC_COM_PIN_OUTPUT_DATA(2), 0xaaaaaaaa }, | ||
| 63 | { DC_COM_PIN_OUTPUT_DATA(1), 0xaaaaaaaa }, | ||
| 64 | { DC_COM_PIN_OUTPUT_DATA(0), 0xaaaaaaaa }, | ||
| 65 | { DC_COM_PIN_OUTPUT_POLARITY(3), 0x00000000 }, | ||
| 66 | { DC_COM_PIN_OUTPUT_POLARITY(2), 0x00000000 }, | ||
| 67 | { DC_COM_PIN_OUTPUT_POLARITY(1), 0x00000000 }, | ||
| 68 | { DC_COM_PIN_OUTPUT_POLARITY(0), 0x00000000 }, | ||
| 69 | { DC_COM_PIN_OUTPUT_ENABLE(3), 0x55555555 }, | ||
| 70 | { DC_COM_PIN_OUTPUT_ENABLE(2), 0x55555555 }, | ||
| 71 | { DC_COM_PIN_OUTPUT_ENABLE(1), 0x55150005 }, | ||
| 72 | { DC_COM_PIN_OUTPUT_ENABLE(0), 0x55555555 }, | ||
| 73 | }; | ||
| 74 | |||
| 75 | static void tegra_dc_write_regs(struct tegra_dc *dc, | ||
| 76 | const struct reg_entry *table, | ||
| 77 | unsigned int num) | ||
| 78 | { | ||
| 79 | unsigned int i; | ||
| 80 | |||
| 81 | for (i = 0; i < num; i++) | ||
| 82 | tegra_dc_writel(dc, table[i].value, table[i].offset); | ||
| 83 | } | ||
| 84 | |||
| 85 | static int tegra_output_rgb_enable(struct tegra_output *output) | ||
| 86 | { | ||
| 87 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
| 88 | |||
| 89 | tegra_dc_write_regs(dc, rgb_enable, ARRAY_SIZE(rgb_enable)); | ||
| 90 | |||
| 91 | return 0; | ||
| 92 | } | ||
| 93 | |||
| 94 | static int tegra_output_rgb_disable(struct tegra_output *output) | ||
| 95 | { | ||
| 96 | struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc); | ||
| 97 | |||
| 98 | tegra_dc_write_regs(dc, rgb_disable, ARRAY_SIZE(rgb_disable)); | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | static int tegra_output_rgb_setup_clock(struct tegra_output *output, | ||
| 104 | struct clk *clk, unsigned long pclk) | ||
| 105 | { | ||
| 106 | struct tegra_rgb *rgb = to_rgb(output); | ||
| 107 | |||
| 108 | return clk_set_parent(clk, rgb->clk_parent); | ||
| 109 | } | ||
| 110 | |||
| 111 | static int tegra_output_rgb_check_mode(struct tegra_output *output, | ||
| 112 | struct drm_display_mode *mode, | ||
| 113 | enum drm_mode_status *status) | ||
| 114 | { | ||
| 115 | /* | ||
| 116 | * FIXME: For now, always assume that the mode is okay. There are | ||
| 117 | * unresolved issues with clk_round_rate(), which doesn't always | ||
| 118 | * reliably report whether a frequency can be set or not. | ||
| 119 | */ | ||
| 120 | |||
| 121 | *status = MODE_OK; | ||
| 122 | |||
| 123 | return 0; | ||
| 124 | } | ||
| 125 | |||
| 126 | static const struct tegra_output_ops rgb_ops = { | ||
| 127 | .enable = tegra_output_rgb_enable, | ||
| 128 | .disable = tegra_output_rgb_disable, | ||
| 129 | .setup_clock = tegra_output_rgb_setup_clock, | ||
| 130 | .check_mode = tegra_output_rgb_check_mode, | ||
| 131 | }; | ||
| 132 | |||
| 133 | int tegra_dc_rgb_probe(struct tegra_dc *dc) | ||
| 134 | { | ||
| 135 | struct device_node *np; | ||
| 136 | struct tegra_rgb *rgb; | ||
| 137 | int err; | ||
| 138 | |||
| 139 | np = of_get_child_by_name(dc->dev->of_node, "rgb"); | ||
| 140 | if (!np || !of_device_is_available(np)) | ||
| 141 | return -ENODEV; | ||
| 142 | |||
| 143 | rgb = devm_kzalloc(dc->dev, sizeof(*rgb), GFP_KERNEL); | ||
| 144 | if (!rgb) | ||
| 145 | return -ENOMEM; | ||
| 146 | |||
| 147 | rgb->output.dev = dc->dev; | ||
| 148 | rgb->output.of_node = np; | ||
| 149 | |||
| 150 | err = tegra_output_parse_dt(&rgb->output); | ||
| 151 | if (err < 0) | ||
| 152 | return err; | ||
| 153 | |||
| 154 | rgb->clk = devm_clk_get(dc->dev, NULL); | ||
| 155 | if (IS_ERR(rgb->clk)) { | ||
| 156 | dev_err(dc->dev, "failed to get clock\n"); | ||
| 157 | return PTR_ERR(rgb->clk); | ||
| 158 | } | ||
| 159 | |||
| 160 | rgb->clk_parent = devm_clk_get(dc->dev, "parent"); | ||
| 161 | if (IS_ERR(rgb->clk_parent)) { | ||
| 162 | dev_err(dc->dev, "failed to get parent clock\n"); | ||
| 163 | return PTR_ERR(rgb->clk_parent); | ||
| 164 | } | ||
| 165 | |||
| 166 | err = clk_set_parent(rgb->clk, rgb->clk_parent); | ||
| 167 | if (err < 0) { | ||
| 168 | dev_err(dc->dev, "failed to set parent clock: %d\n", err); | ||
| 169 | return err; | ||
| 170 | } | ||
| 171 | |||
| 172 | dc->rgb = &rgb->output; | ||
| 173 | |||
| 174 | return 0; | ||
| 175 | } | ||
| 176 | |||
| 177 | int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc) | ||
| 178 | { | ||
| 179 | struct tegra_rgb *rgb = to_rgb(dc->rgb); | ||
| 180 | int err; | ||
| 181 | |||
| 182 | if (!dc->rgb) | ||
| 183 | return -ENODEV; | ||
| 184 | |||
| 185 | rgb->output.type = TEGRA_OUTPUT_RGB; | ||
| 186 | rgb->output.ops = &rgb_ops; | ||
| 187 | |||
| 188 | err = tegra_output_init(dc->base.dev, &rgb->output); | ||
| 189 | if (err < 0) { | ||
| 190 | dev_err(dc->dev, "output setup failed: %d\n", err); | ||
| 191 | return err; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* | ||
| 195 | * By default, outputs can be associated with each display controller. | ||
| 196 | * RGB outputs are an exception, so we make sure they can be attached | ||
| 197 | * to only their parent display controller. | ||
| 198 | */ | ||
| 199 | rgb->output.encoder.possible_crtcs = 1 << dc->pipe; | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | int tegra_dc_rgb_exit(struct tegra_dc *dc) | ||
| 205 | { | ||
| 206 | if (dc->rgb) { | ||
| 207 | int err; | ||
| 208 | |||
| 209 | err = tegra_output_disable(dc->rgb); | ||
| 210 | if (err < 0) { | ||
| 211 | dev_err(dc->dev, "output failed to disable: %d\n", err); | ||
| 212 | return err; | ||
| 213 | } | ||
| 214 | |||
| 215 | err = tegra_output_exit(dc->rgb); | ||
| 216 | if (err < 0) { | ||
| 217 | dev_err(dc->dev, "output cleanup failed: %d\n", err); | ||
| 218 | return err; | ||
| 219 | } | ||
| 220 | |||
| 221 | dc->rgb = NULL; | ||
| 222 | } | ||
| 223 | |||
| 224 | return 0; | ||
| 225 | } | ||
