aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/tegra
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video/tegra')
-rw-r--r--drivers/video/tegra/Kconfig126
-rw-r--r--drivers/video/tegra/Makefile5
-rw-r--r--drivers/video/tegra/dc/Makefile10
-rw-r--r--drivers/video/tegra/dc/dc.c3120
-rw-r--r--drivers/video/tegra/dc/dc_priv.h220
-rw-r--r--drivers/video/tegra/dc/dc_reg.h555
-rw-r--r--drivers/video/tegra/dc/dc_sysfs.c327
-rw-r--r--drivers/video/tegra/dc/dsi.c3042
-rw-r--r--drivers/video/tegra/dc/dsi.h375
-rw-r--r--drivers/video/tegra/dc/dsi_regs.h351
-rw-r--r--drivers/video/tegra/dc/edid.c619
-rw-r--r--drivers/video/tegra/dc/edid.h62
-rw-r--r--drivers/video/tegra/dc/ext/Makefile5
-rw-r--r--drivers/video/tegra/dc/ext/control.c279
-rw-r--r--drivers/video/tegra/dc/ext/cursor.c203
-rw-r--r--drivers/video/tegra/dc/ext/dev.c975
-rw-r--r--drivers/video/tegra/dc/ext/events.c197
-rw-r--r--drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h147
-rw-r--r--drivers/video/tegra/dc/ext/util.c78
-rw-r--r--drivers/video/tegra/dc/hdmi.c2381
-rw-r--r--drivers/video/tegra/dc/hdmi.h222
-rw-r--r--drivers/video/tegra/dc/hdmi_reg.h478
-rw-r--r--drivers/video/tegra/dc/nvhdcp.c1259
-rw-r--r--drivers/video/tegra/dc/nvhdcp.h46
-rw-r--r--drivers/video/tegra/dc/nvsd.c906
-rw-r--r--drivers/video/tegra/dc/nvsd.h25
-rw-r--r--drivers/video/tegra/dc/rgb.c160
-rw-r--r--drivers/video/tegra/fb.c625
-rw-r--r--drivers/video/tegra/host/Makefile23
-rw-r--r--drivers/video/tegra/host/bus.c569
-rw-r--r--drivers/video/tegra/host/bus_client.c606
-rw-r--r--drivers/video/tegra/host/bus_client.h39
-rw-r--r--drivers/video/tegra/host/chip_support.h141
-rw-r--r--drivers/video/tegra/host/debug.c167
-rw-r--r--drivers/video/tegra/host/debug.h50
-rw-r--r--drivers/video/tegra/host/dev.c635
-rw-r--r--drivers/video/tegra/host/dev.h68
-rw-r--r--drivers/video/tegra/host/dsi/Makefile7
-rw-r--r--drivers/video/tegra/host/dsi/dsi.c82
-rw-r--r--drivers/video/tegra/host/gr2d/Makefile7
-rw-r--r--drivers/video/tegra/host/gr2d/gr2d.c82
-rw-r--r--drivers/video/tegra/host/gr3d/Makefile10
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.c211
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d.h54
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.c395
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t20.h30
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.c435
-rw-r--r--drivers/video/tegra/host/gr3d/gr3d_t30.h30
-rw-r--r--drivers/video/tegra/host/gr3d/scale3d.c661
-rw-r--r--drivers/video/tegra/host/gr3d/scale3d.h47
-rw-r--r--drivers/video/tegra/host/host1x/Makefile12
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.c665
-rw-r--r--drivers/video/tegra/host/host1x/host1x_cdma.h41
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.c627
-rw-r--r--drivers/video/tegra/host/host1x/host1x_channel.h45
-rw-r--r--drivers/video/tegra/host/host1x/host1x_debug.c404
-rw-r--r--drivers/video/tegra/host/host1x/host1x_hardware.h274
-rw-r--r--drivers/video/tegra/host/host1x/host1x_hwctx.h65
-rw-r--r--drivers/video/tegra/host/host1x/host1x_intr.c218
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.c248
-rw-r--r--drivers/video/tegra/host/host1x/host1x_syncpt.h77
-rw-r--r--drivers/video/tegra/host/isp/Makefile7
-rw-r--r--drivers/video/tegra/host/isp/isp.c82
-rw-r--r--drivers/video/tegra/host/mpe/Makefile7
-rw-r--r--drivers/video/tegra/host/mpe/mpe.c638
-rw-r--r--drivers/video/tegra/host/mpe/mpe.h32
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c467
-rw-r--r--drivers/video/tegra/host/nvhost_acm.h60
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.c508
-rw-r--r--drivers/video/tegra/host/nvhost_cdma.h133
-rw-r--r--drivers/video/tegra/host/nvhost_channel.c158
-rw-r--r--drivers/video/tegra/host/nvhost_channel.h86
-rw-r--r--drivers/video/tegra/host/nvhost_hwctx.h67
-rw-r--r--drivers/video/tegra/host/nvhost_intr.c428
-rw-r--r--drivers/video/tegra/host/nvhost_intr.h115
-rw-r--r--drivers/video/tegra/host/nvhost_job.c339
-rw-r--r--drivers/video/tegra/host/nvhost_job.h150
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.c319
-rw-r--r--drivers/video/tegra/host/nvhost_syncpt.h155
-rw-r--r--drivers/video/tegra/host/t20/Makefile8
-rw-r--r--drivers/video/tegra/host/t20/t20.c233
-rw-r--r--drivers/video/tegra/host/t20/t20.h33
-rw-r--r--drivers/video/tegra/host/t30/Makefile8
-rw-r--r--drivers/video/tegra/host/t30/t30.c251
-rw-r--r--drivers/video/tegra/host/t30/t30.h29
-rw-r--r--drivers/video/tegra/host/vi/Makefile7
-rw-r--r--drivers/video/tegra/host/vi/vi.c82
-rw-r--r--drivers/video/tegra/nvmap/Makefile7
-rw-r--r--drivers/video/tegra/nvmap/nvmap.c871
-rw-r--r--drivers/video/tegra/nvmap/nvmap.h271
-rw-r--r--drivers/video/tegra/nvmap/nvmap_common.h38
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c1436
-rw-r--r--drivers/video/tegra/nvmap/nvmap_handle.c1020
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.c1113
-rw-r--r--drivers/video/tegra/nvmap/nvmap_heap.h68
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.c749
-rw-r--r--drivers/video/tegra/nvmap/nvmap_ioctl.h159
-rw-r--r--drivers/video/tegra/nvmap/nvmap_mru.c187
-rw-r--r--drivers/video/tegra/nvmap/nvmap_mru.h84
99 files changed, 34228 insertions, 0 deletions
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
new file mode 100644
index 00000000000..7de26267155
--- /dev/null
+++ b/drivers/video/tegra/Kconfig
@@ -0,0 +1,126 @@
1if ARCH_TEGRA
2
3comment "NVIDIA Tegra Display Driver options"
4
5config TEGRA_GRHOST
6 tristate "Tegra graphics host driver"
7 help
8 Driver for the Tegra graphics host hardware.
9
10config TEGRA_DC
11 tristate "Tegra Display Contoller"
12 depends on ARCH_TEGRA && TEGRA_GRHOST
13 select FB_MODE_HELPERS
14 select I2C
15 help
16 Tegra display controller support.
17
18config FB_TEGRA
19 tristate "Tegra Framebuffer driver"
20 depends on TEGRA_DC && FB = y
21 select FB_CFB_FILLRECT
22 select FB_CFB_COPYAREA
23 select FB_CFB_IMAGEBLIT
24 default FB
25 help
26 Framebuffer device support for the Tegra display controller.
27
28config TEGRA_DC_EXTENSIONS
29 bool "Tegra Display Controller Extensions"
30 depends on TEGRA_DC
31 default y
32 help
33 This exposes support for extended capabilities of the Tegra display
34 controller to userspace drivers.
35
36config TEGRA_NVMAP
37 bool "Tegra GPU memory management driver (nvmap)"
38 default y
39 help
40 Say Y here to include the memory management driver for the Tegra
41 GPU, multimedia and display subsystems
42
43config NVMAP_RECLAIM_UNPINNED_VM
44 bool "Virtualize IOVMM memory in nvmap"
45 depends on TEGRA_NVMAP && TEGRA_IOVMM
46 default y
47 help
48 Say Y here to enable nvmap to reclaim I/O virtual memory after
49 it has been unpinned, and re-use it for other handles. This can
50 allow a larger virtual I/O VM space than would normally be
51 supported by the hardware, at a slight cost in performance.
52
53config NVMAP_ALLOW_SYSMEM
54 bool "Allow physical system memory to be used by nvmap"
55 depends on TEGRA_NVMAP
56 default y
57 help
58 Say Y here to allow nvmap to use physical system memory (i.e.,
59 shared with the operating system but not translated through
60 an IOVMM device) for allocations.
61
62config NVMAP_HIGHMEM_ONLY
63 bool "Use only HIGHMEM for nvmap"
64 depends on TEGRA_NVMAP && (NVMAP_ALLOW_SYSMEM || TEGRA_IOVMM) && HIGHMEM
65 default n
66 help
67 Say Y here to restrict nvmap system memory allocations (both
68 physical system memory and IOVMM) to just HIGHMEM pages.
69
70config NVMAP_CARVEOUT_KILLER
71 bool "Reclaim nvmap carveout by killing processes"
72 depends on TEGRA_NVMAP
73 default n
74 help
75 Say Y here to allow the system to reclaim carveout space by killing
76 processes. This will kill the largest consumers of lowest priority
77 first.
78
79config NVMAP_CARVEOUT_COMPACTOR
80 bool "Compact carveout when it gets fragmented"
81 depends on TEGRA_NVMAP
82 default y
83 help
84 When carveout allocation attempt fails, compactor defragements
85 heap and retries the failed allocation.
86 Say Y here to let nvmap to keep carveout fragmentation under control.
87
88
89config NVMAP_VPR
90 bool "Enable VPR Heap."
91 depends on TEGRA_NVMAP
92 default n
93 help
94 Say Y here to enable Video Protection Region(VPR) heap.
95 if unsure, say N.
96
97config TEGRA_DSI
98 bool "Enable DSI panel."
99 default n
100 help
101 Say Y here to enable the DSI panel.
102
103config NVMAP_CONVERT_CARVEOUT_TO_IOVMM
104 bool "Convert carveout to IOVMM"
105 depends on TEGRA_NVMAP && TEGRA_IOVMM_SMMU
106 default y
107 help
108 Say Y here to force to convert carveout memory requests to
109 I/O virtual memory requests.
110
111config TEGRA_NVHDCP
112 bool "Support NVHDCP content protection on HDMI"
113 default n
114 help
115 Say Y here to support NVHDCP upstream and downstream protocols, this
116 requires a correctly fused chip to negotiate keys.
117
118config TEGRA_HDMI_74MHZ_LIMIT
119 bool "Support only up to 74.25 MHz HDMI pixel frequency"
120 default n
121 help
122 Say Y here to make kernel report only low bandwidth modes.
123 Useful only for boards which can't deliver 148.50 MHz.
124
125endif
126
diff --git a/drivers/video/tegra/Makefile b/drivers/video/tegra/Makefile
new file mode 100644
index 00000000000..2299a3c5eaa
--- /dev/null
+++ b/drivers/video/tegra/Makefile
@@ -0,0 +1,5 @@
1GCOV_PROFILE := y
2obj-$(CONFIG_TEGRA_GRHOST) += host/
3obj-$(CONFIG_TEGRA_DC) += dc/
4obj-$(CONFIG_FB_TEGRA) += fb.o
5obj-$(CONFIG_TEGRA_NVMAP) += nvmap/
diff --git a/drivers/video/tegra/dc/Makefile b/drivers/video/tegra/dc/Makefile
new file mode 100644
index 00000000000..01f13918ca6
--- /dev/null
+++ b/drivers/video/tegra/dc/Makefile
@@ -0,0 +1,10 @@
1GCOV_PROFILE := y
2obj-y += dc.o
3obj-y += rgb.o
4obj-y += hdmi.o
5obj-$(CONFIG_TEGRA_NVHDCP) += nvhdcp.o
6obj-y += edid.o
7obj-y += nvsd.o
8obj-y += dsi.o
9obj-y += dc_sysfs.o
10obj-$(CONFIG_TEGRA_DC_EXTENSIONS) += ext/
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
new file mode 100644
index 00000000000..8b3bf041a7d
--- /dev/null
+++ b/drivers/video/tegra/dc/dc.c
@@ -0,0 +1,3120 @@
1/*
2 * drivers/video/tegra/dc/dc.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2010-2012 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/module.h>
21#include <linux/kernel.h>
22#include <linux/err.h>
23#include <linux/errno.h>
24#include <linux/interrupt.h>
25#include <linux/slab.h>
26#include <linux/io.h>
27#include <linux/clk.h>
28#include <linux/mutex.h>
29#include <linux/delay.h>
30#include <linux/dma-mapping.h>
31#include <linux/workqueue.h>
32#include <linux/ktime.h>
33#include <linux/debugfs.h>
34#include <linux/seq_file.h>
35#include <linux/backlight.h>
36#include <video/tegrafb.h>
37#include <drm/drm_fixed.h>
38#ifdef CONFIG_SWITCH
39#include <linux/switch.h>
40#endif
41
42
43#include <mach/clk.h>
44#include <mach/dc.h>
45#include <mach/fb.h>
46#include <mach/mc.h>
47#include <linux/nvhost.h>
48#include <mach/latency_allowance.h>
49
50#include "dc_reg.h"
51#include "dc_priv.h"
52#include "nvsd.h"
53
54#define TEGRA_CRC_LATCHED_DELAY 34
55
56#define DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL 0x01000000
57#define DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL 0x0
58
59#ifndef CONFIG_TEGRA_FPGA_PLATFORM
60#define ALL_UF_INT (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT)
61#else
62/* ignore underflows when on simulation and fpga platform */
63#define ALL_UF_INT (0)
64#endif
65
66static int no_vsync;
67
68static void _tegra_dc_controller_disable(struct tegra_dc *dc);
69
70module_param_named(no_vsync, no_vsync, int, S_IRUGO | S_IWUSR);
71
72static int use_dynamic_emc = 1;
73
74module_param_named(use_dynamic_emc, use_dynamic_emc, int, S_IRUGO | S_IWUSR);
75
76struct tegra_dc *tegra_dcs[TEGRA_MAX_DC];
77
78DEFINE_MUTEX(tegra_dc_lock);
79DEFINE_MUTEX(shared_lock);
80
81static const struct {
82 bool h;
83 bool v;
84} can_filter[] = {
85 /* Window A has no filtering */
86 { false, false },
87 /* Window B has both H and V filtering */
88 { true, true },
89 /* Window C has only H filtering */
90 { false, true },
91};
92static inline bool win_use_v_filter(const struct tegra_dc_win *win)
93{
94 return can_filter[win->idx].v &&
95 win->h.full != dfixed_const(win->out_h);
96}
97static inline bool win_use_h_filter(const struct tegra_dc_win *win)
98{
99 return can_filter[win->idx].h &&
100 win->w.full != dfixed_const(win->out_w);
101}
102
103static inline int tegra_dc_fmt_bpp(int fmt)
104{
105 switch (fmt) {
106 case TEGRA_WIN_FMT_P1:
107 return 1;
108
109 case TEGRA_WIN_FMT_P2:
110 return 2;
111
112 case TEGRA_WIN_FMT_P4:
113 return 4;
114
115 case TEGRA_WIN_FMT_P8:
116 return 8;
117
118 case TEGRA_WIN_FMT_B4G4R4A4:
119 case TEGRA_WIN_FMT_B5G5R5A:
120 case TEGRA_WIN_FMT_B5G6R5:
121 case TEGRA_WIN_FMT_AB5G5R5:
122 return 16;
123
124 case TEGRA_WIN_FMT_B8G8R8A8:
125 case TEGRA_WIN_FMT_R8G8B8A8:
126 case TEGRA_WIN_FMT_B6x2G6x2R6x2A8:
127 case TEGRA_WIN_FMT_R6x2G6x2B6x2A8:
128 return 32;
129
130 /* for planar formats, size of the Y plane, 8bit */
131 case TEGRA_WIN_FMT_YCbCr420P:
132 case TEGRA_WIN_FMT_YUV420P:
133 case TEGRA_WIN_FMT_YCbCr422P:
134 case TEGRA_WIN_FMT_YUV422P:
135 case TEGRA_WIN_FMT_YCbCr422R:
136 case TEGRA_WIN_FMT_YUV422R:
137 case TEGRA_WIN_FMT_YCbCr422RA:
138 case TEGRA_WIN_FMT_YUV422RA:
139 return 8;
140
141 case TEGRA_WIN_FMT_YCbCr422:
142 case TEGRA_WIN_FMT_YUV422:
143 /* FIXME: need to know the bpp of these formats */
144 return 0;
145 }
146 return 0;
147}
148
149static inline bool tegra_dc_is_yuv_planar(int fmt)
150{
151 switch (fmt) {
152 case TEGRA_WIN_FMT_YUV420P:
153 case TEGRA_WIN_FMT_YCbCr420P:
154 case TEGRA_WIN_FMT_YCbCr422P:
155 case TEGRA_WIN_FMT_YUV422P:
156 case TEGRA_WIN_FMT_YCbCr422R:
157 case TEGRA_WIN_FMT_YUV422R:
158 case TEGRA_WIN_FMT_YCbCr422RA:
159 case TEGRA_WIN_FMT_YUV422RA:
160 return true;
161 }
162 return false;
163}
164
165#define DUMP_REG(a) do { \
166 snprintf(buff, sizeof(buff), "%-32s\t%03x\t%08lx\n", \
167 #a, a, tegra_dc_readl(dc, a)); \
168 print(data, buff); \
169 } while (0)
170
171static void _dump_regs(struct tegra_dc *dc, void *data,
172 void (* print)(void *data, const char *str))
173{
174 int i;
175 char buff[256];
176
177 tegra_dc_io_start(dc);
178 clk_enable(dc->clk);
179
180 DUMP_REG(DC_CMD_DISPLAY_COMMAND_OPTION0);
181 DUMP_REG(DC_CMD_DISPLAY_COMMAND);
182 DUMP_REG(DC_CMD_SIGNAL_RAISE);
183 DUMP_REG(DC_CMD_INT_STATUS);
184 DUMP_REG(DC_CMD_INT_MASK);
185 DUMP_REG(DC_CMD_INT_ENABLE);
186 DUMP_REG(DC_CMD_INT_TYPE);
187 DUMP_REG(DC_CMD_INT_POLARITY);
188 DUMP_REG(DC_CMD_SIGNAL_RAISE1);
189 DUMP_REG(DC_CMD_SIGNAL_RAISE2);
190 DUMP_REG(DC_CMD_SIGNAL_RAISE3);
191 DUMP_REG(DC_CMD_STATE_ACCESS);
192 DUMP_REG(DC_CMD_STATE_CONTROL);
193 DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
194 DUMP_REG(DC_CMD_REG_ACT_CONTROL);
195
196 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
197 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS1);
198 DUMP_REG(DC_DISP_DISP_WIN_OPTIONS);
199 DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY);
200 DUMP_REG(DC_DISP_MEM_HIGH_PRIORITY_TIMER);
201 DUMP_REG(DC_DISP_DISP_TIMING_OPTIONS);
202 DUMP_REG(DC_DISP_REF_TO_SYNC);
203 DUMP_REG(DC_DISP_SYNC_WIDTH);
204 DUMP_REG(DC_DISP_BACK_PORCH);
205 DUMP_REG(DC_DISP_DISP_ACTIVE);
206 DUMP_REG(DC_DISP_FRONT_PORCH);
207 DUMP_REG(DC_DISP_H_PULSE0_CONTROL);
208 DUMP_REG(DC_DISP_H_PULSE0_POSITION_A);
209 DUMP_REG(DC_DISP_H_PULSE0_POSITION_B);
210 DUMP_REG(DC_DISP_H_PULSE0_POSITION_C);
211 DUMP_REG(DC_DISP_H_PULSE0_POSITION_D);
212 DUMP_REG(DC_DISP_H_PULSE1_CONTROL);
213 DUMP_REG(DC_DISP_H_PULSE1_POSITION_A);
214 DUMP_REG(DC_DISP_H_PULSE1_POSITION_B);
215 DUMP_REG(DC_DISP_H_PULSE1_POSITION_C);
216 DUMP_REG(DC_DISP_H_PULSE1_POSITION_D);
217 DUMP_REG(DC_DISP_H_PULSE2_CONTROL);
218 DUMP_REG(DC_DISP_H_PULSE2_POSITION_A);
219 DUMP_REG(DC_DISP_H_PULSE2_POSITION_B);
220 DUMP_REG(DC_DISP_H_PULSE2_POSITION_C);
221 DUMP_REG(DC_DISP_H_PULSE2_POSITION_D);
222 DUMP_REG(DC_DISP_V_PULSE0_CONTROL);
223 DUMP_REG(DC_DISP_V_PULSE0_POSITION_A);
224 DUMP_REG(DC_DISP_V_PULSE0_POSITION_B);
225 DUMP_REG(DC_DISP_V_PULSE0_POSITION_C);
226 DUMP_REG(DC_DISP_V_PULSE1_CONTROL);
227 DUMP_REG(DC_DISP_V_PULSE1_POSITION_A);
228 DUMP_REG(DC_DISP_V_PULSE1_POSITION_B);
229 DUMP_REG(DC_DISP_V_PULSE1_POSITION_C);
230 DUMP_REG(DC_DISP_V_PULSE2_CONTROL);
231 DUMP_REG(DC_DISP_V_PULSE2_POSITION_A);
232 DUMP_REG(DC_DISP_V_PULSE3_CONTROL);
233 DUMP_REG(DC_DISP_V_PULSE3_POSITION_A);
234 DUMP_REG(DC_DISP_M0_CONTROL);
235 DUMP_REG(DC_DISP_M1_CONTROL);
236 DUMP_REG(DC_DISP_DI_CONTROL);
237 DUMP_REG(DC_DISP_PP_CONTROL);
238 DUMP_REG(DC_DISP_PP_SELECT_A);
239 DUMP_REG(DC_DISP_PP_SELECT_B);
240 DUMP_REG(DC_DISP_PP_SELECT_C);
241 DUMP_REG(DC_DISP_PP_SELECT_D);
242 DUMP_REG(DC_DISP_DISP_CLOCK_CONTROL);
243 DUMP_REG(DC_DISP_DISP_INTERFACE_CONTROL);
244 DUMP_REG(DC_DISP_DISP_COLOR_CONTROL);
245 DUMP_REG(DC_DISP_SHIFT_CLOCK_OPTIONS);
246 DUMP_REG(DC_DISP_DATA_ENABLE_OPTIONS);
247 DUMP_REG(DC_DISP_SERIAL_INTERFACE_OPTIONS);
248 DUMP_REG(DC_DISP_LCD_SPI_OPTIONS);
249 DUMP_REG(DC_DISP_BORDER_COLOR);
250 DUMP_REG(DC_DISP_COLOR_KEY0_LOWER);
251 DUMP_REG(DC_DISP_COLOR_KEY0_UPPER);
252 DUMP_REG(DC_DISP_COLOR_KEY1_LOWER);
253 DUMP_REG(DC_DISP_COLOR_KEY1_UPPER);
254 DUMP_REG(DC_DISP_CURSOR_FOREGROUND);
255 DUMP_REG(DC_DISP_CURSOR_BACKGROUND);
256 DUMP_REG(DC_DISP_CURSOR_START_ADDR);
257 DUMP_REG(DC_DISP_CURSOR_START_ADDR_NS);
258 DUMP_REG(DC_DISP_CURSOR_POSITION);
259 DUMP_REG(DC_DISP_CURSOR_POSITION_NS);
260 DUMP_REG(DC_DISP_INIT_SEQ_CONTROL);
261 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_A);
262 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_B);
263 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_C);
264 DUMP_REG(DC_DISP_SPI_INIT_SEQ_DATA_D);
265 DUMP_REG(DC_DISP_DC_MCCIF_FIFOCTRL);
266 DUMP_REG(DC_DISP_MCCIF_DISPLAY0A_HYST);
267 DUMP_REG(DC_DISP_MCCIF_DISPLAY0B_HYST);
268 DUMP_REG(DC_DISP_MCCIF_DISPLAY0C_HYST);
269 DUMP_REG(DC_DISP_MCCIF_DISPLAY1B_HYST);
270 DUMP_REG(DC_DISP_DAC_CRT_CTRL);
271 DUMP_REG(DC_DISP_DISP_MISC_CONTROL);
272
273
274 for (i = 0; i < 3; i++) {
275 print(data, "\n");
276 snprintf(buff, sizeof(buff), "WINDOW %c:\n", 'A' + i);
277 print(data, buff);
278
279 tegra_dc_writel(dc, WINDOW_A_SELECT << i,
280 DC_CMD_DISPLAY_WINDOW_HEADER);
281 DUMP_REG(DC_CMD_DISPLAY_WINDOW_HEADER);
282 DUMP_REG(DC_WIN_WIN_OPTIONS);
283 DUMP_REG(DC_WIN_BYTE_SWAP);
284 DUMP_REG(DC_WIN_BUFFER_CONTROL);
285 DUMP_REG(DC_WIN_COLOR_DEPTH);
286 DUMP_REG(DC_WIN_POSITION);
287 DUMP_REG(DC_WIN_SIZE);
288 DUMP_REG(DC_WIN_PRESCALED_SIZE);
289 DUMP_REG(DC_WIN_H_INITIAL_DDA);
290 DUMP_REG(DC_WIN_V_INITIAL_DDA);
291 DUMP_REG(DC_WIN_DDA_INCREMENT);
292 DUMP_REG(DC_WIN_LINE_STRIDE);
293 DUMP_REG(DC_WIN_BUF_STRIDE);
294 DUMP_REG(DC_WIN_UV_BUF_STRIDE);
295 DUMP_REG(DC_WIN_BLEND_NOKEY);
296 DUMP_REG(DC_WIN_BLEND_1WIN);
297 DUMP_REG(DC_WIN_BLEND_2WIN_X);
298 DUMP_REG(DC_WIN_BLEND_2WIN_Y);
299 DUMP_REG(DC_WIN_BLEND_3WIN_XY);
300 DUMP_REG(DC_WINBUF_START_ADDR);
301 DUMP_REG(DC_WINBUF_START_ADDR_U);
302 DUMP_REG(DC_WINBUF_START_ADDR_V);
303 DUMP_REG(DC_WINBUF_ADDR_H_OFFSET);
304 DUMP_REG(DC_WINBUF_ADDR_V_OFFSET);
305 DUMP_REG(DC_WINBUF_UFLOW_STATUS);
306 DUMP_REG(DC_WIN_CSC_YOF);
307 DUMP_REG(DC_WIN_CSC_KYRGB);
308 DUMP_REG(DC_WIN_CSC_KUR);
309 DUMP_REG(DC_WIN_CSC_KVR);
310 DUMP_REG(DC_WIN_CSC_KUG);
311 DUMP_REG(DC_WIN_CSC_KVG);
312 DUMP_REG(DC_WIN_CSC_KUB);
313 DUMP_REG(DC_WIN_CSC_KVB);
314 }
315
316 DUMP_REG(DC_CMD_DISPLAY_POWER_CONTROL);
317 DUMP_REG(DC_COM_PIN_OUTPUT_ENABLE2);
318 DUMP_REG(DC_COM_PIN_OUTPUT_POLARITY2);
319 DUMP_REG(DC_COM_PIN_OUTPUT_DATA2);
320 DUMP_REG(DC_COM_PIN_INPUT_ENABLE2);
321 DUMP_REG(DC_COM_PIN_OUTPUT_SELECT5);
322 DUMP_REG(DC_DISP_DISP_SIGNAL_OPTIONS0);
323 DUMP_REG(DC_DISP_M1_CONTROL);
324 DUMP_REG(DC_COM_PM1_CONTROL);
325 DUMP_REG(DC_COM_PM1_DUTY_CYCLE);
326 DUMP_REG(DC_DISP_SD_CONTROL);
327
328 clk_disable(dc->clk);
329 tegra_dc_io_end(dc);
330}
331
332#undef DUMP_REG
333
334#ifdef DEBUG
335static void dump_regs_print(void *data, const char *str)
336{
337 struct tegra_dc *dc = data;
338 dev_dbg(&dc->ndev->dev, "%s", str);
339}
340
341static void dump_regs(struct tegra_dc *dc)
342{
343 _dump_regs(dc, dc, dump_regs_print);
344}
345#else /* !DEBUG */
346
347static void dump_regs(struct tegra_dc *dc) {}
348
349#endif /* DEBUG */
350
351#ifdef CONFIG_DEBUG_FS
352
353static void dbg_regs_print(void *data, const char *str)
354{
355 struct seq_file *s = data;
356
357 seq_printf(s, "%s", str);
358}
359
360#undef DUMP_REG
361
362static int dbg_dc_show(struct seq_file *s, void *unused)
363{
364 struct tegra_dc *dc = s->private;
365
366 _dump_regs(dc, s, dbg_regs_print);
367
368 return 0;
369}
370
371
372static int dbg_dc_open(struct inode *inode, struct file *file)
373{
374 return single_open(file, dbg_dc_show, inode->i_private);
375}
376
377static const struct file_operations regs_fops = {
378 .open = dbg_dc_open,
379 .read = seq_read,
380 .llseek = seq_lseek,
381 .release = single_release,
382};
383
384static int dbg_dc_mode_show(struct seq_file *s, void *unused)
385{
386 struct tegra_dc *dc = s->private;
387 struct tegra_dc_mode *m;
388
389 mutex_lock(&dc->lock);
390 m = &dc->mode;
391 seq_printf(s,
392 "pclk: %d\n"
393 "h_ref_to_sync: %d\n"
394 "v_ref_to_sync: %d\n"
395 "h_sync_width: %d\n"
396 "v_sync_width: %d\n"
397 "h_back_porch: %d\n"
398 "v_back_porch: %d\n"
399 "h_active: %d\n"
400 "v_active: %d\n"
401 "h_front_porch: %d\n"
402 "v_front_porch: %d\n"
403 "stereo_mode: %d\n",
404 m->pclk, m->h_ref_to_sync, m->v_ref_to_sync,
405 m->h_sync_width, m->v_sync_width,
406 m->h_back_porch, m->v_back_porch,
407 m->h_active, m->v_active,
408 m->h_front_porch, m->v_front_porch,
409 m->stereo_mode);
410 mutex_unlock(&dc->lock);
411 return 0;
412}
413
414static int dbg_dc_mode_open(struct inode *inode, struct file *file)
415{
416 return single_open(file, dbg_dc_mode_show, inode->i_private);
417}
418
419static const struct file_operations mode_fops = {
420 .open = dbg_dc_mode_open,
421 .read = seq_read,
422 .llseek = seq_lseek,
423 .release = single_release,
424};
425
426static int dbg_dc_stats_show(struct seq_file *s, void *unused)
427{
428 struct tegra_dc *dc = s->private;
429
430 mutex_lock(&dc->lock);
431 seq_printf(s,
432 "underflows: %llu\n"
433 "underflows_a: %llu\n"
434 "underflows_b: %llu\n"
435 "underflows_c: %llu\n",
436 dc->stats.underflows,
437 dc->stats.underflows_a,
438 dc->stats.underflows_b,
439 dc->stats.underflows_c);
440 mutex_unlock(&dc->lock);
441
442 return 0;
443}
444
445static int dbg_dc_stats_open(struct inode *inode, struct file *file)
446{
447 return single_open(file, dbg_dc_stats_show, inode->i_private);
448}
449
450static const struct file_operations stats_fops = {
451 .open = dbg_dc_stats_open,
452 .read = seq_read,
453 .llseek = seq_lseek,
454 .release = single_release,
455};
456
457static void __devexit tegra_dc_remove_debugfs(struct tegra_dc *dc)
458{
459 if (dc->debugdir)
460 debugfs_remove_recursive(dc->debugdir);
461 dc->debugdir = NULL;
462}
463
464static void tegra_dc_create_debugfs(struct tegra_dc *dc)
465{
466 struct dentry *retval;
467
468 dc->debugdir = debugfs_create_dir(dev_name(&dc->ndev->dev), NULL);
469 if (!dc->debugdir)
470 goto remove_out;
471
472 retval = debugfs_create_file("regs", S_IRUGO, dc->debugdir, dc,
473 &regs_fops);
474 if (!retval)
475 goto remove_out;
476
477 retval = debugfs_create_file("mode", S_IRUGO, dc->debugdir, dc,
478 &mode_fops);
479 if (!retval)
480 goto remove_out;
481
482 retval = debugfs_create_file("stats", S_IRUGO, dc->debugdir, dc,
483 &stats_fops);
484 if (!retval)
485 goto remove_out;
486
487 return;
488remove_out:
489 dev_err(&dc->ndev->dev, "could not create debugfs\n");
490 tegra_dc_remove_debugfs(dc);
491}
492
493#else /* !CONFIG_DEBUGFS */
494static inline void tegra_dc_create_debugfs(struct tegra_dc *dc) { };
495static inline void __devexit tegra_dc_remove_debugfs(struct tegra_dc *dc) { };
496#endif /* CONFIG_DEBUGFS */
497
498static int tegra_dc_set(struct tegra_dc *dc, int index)
499{
500 int ret = 0;
501
502 mutex_lock(&tegra_dc_lock);
503 if (index >= TEGRA_MAX_DC) {
504 ret = -EINVAL;
505 goto out;
506 }
507
508 if (dc != NULL && tegra_dcs[index] != NULL) {
509 ret = -EBUSY;
510 goto out;
511 }
512
513 tegra_dcs[index] = dc;
514
515out:
516 mutex_unlock(&tegra_dc_lock);
517
518 return ret;
519}
520
521static unsigned int tegra_dc_has_multiple_dc(void)
522{
523 unsigned int idx;
524 unsigned int cnt = 0;
525 struct tegra_dc *dc;
526
527 mutex_lock(&tegra_dc_lock);
528 for (idx = 0; idx < TEGRA_MAX_DC; idx++)
529 cnt += ((dc = tegra_dcs[idx]) != NULL && dc->enabled) ? 1 : 0;
530 mutex_unlock(&tegra_dc_lock);
531
532 return (cnt > 1);
533}
534
535struct tegra_dc *tegra_dc_get_dc(unsigned idx)
536{
537 if (idx < TEGRA_MAX_DC)
538 return tegra_dcs[idx];
539 else
540 return NULL;
541}
542EXPORT_SYMBOL(tegra_dc_get_dc);
543
544struct tegra_dc_win *tegra_dc_get_window(struct tegra_dc *dc, unsigned win)
545{
546 if (win >= dc->n_windows)
547 return NULL;
548
549 return &dc->windows[win];
550}
551EXPORT_SYMBOL(tegra_dc_get_window);
552
553static int get_topmost_window(u32 *depths, unsigned long *wins)
554{
555 int idx, best = -1;
556
557 for_each_set_bit(idx, wins, DC_N_WINDOWS) {
558 if (best == -1 || depths[idx] < depths[best])
559 best = idx;
560 }
561 clear_bit(best, wins);
562 return best;
563}
564
565bool tegra_dc_get_connected(struct tegra_dc *dc)
566{
567 return dc->connected;
568}
569EXPORT_SYMBOL(tegra_dc_get_connected);
570
571static u32 blend_topwin(u32 flags)
572{
573 if (flags & TEGRA_WIN_FLAG_BLEND_COVERAGE)
574 return BLEND(NOKEY, ALPHA, 0xff, 0xff);
575 else if (flags & TEGRA_WIN_FLAG_BLEND_PREMULT)
576 return BLEND(NOKEY, PREMULT, 0xff, 0xff);
577 else
578 return BLEND(NOKEY, FIX, 0xff, 0xff);
579}
580
581static u32 blend_2win(int idx, unsigned long behind_mask, u32* flags, int xy)
582{
583 int other;
584
585 for (other = 0; other < DC_N_WINDOWS; other++) {
586 if (other != idx && (xy-- == 0))
587 break;
588 }
589 if (BIT(other) & behind_mask)
590 return blend_topwin(flags[idx]);
591 else if (flags[other])
592 return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
593 else
594 return BLEND(NOKEY, FIX, 0x00, 0x00);
595}
596
597static u32 blend_3win(int idx, unsigned long behind_mask, u32* flags)
598{
599 unsigned long infront_mask;
600 int first;
601
602 infront_mask = ~(behind_mask | BIT(idx));
603 infront_mask &= (BIT(DC_N_WINDOWS) - 1);
604 first = ffs(infront_mask) - 1;
605
606 if (!infront_mask)
607 return blend_topwin(flags[idx]);
608 else if (behind_mask && first != -1 && flags[first])
609 return BLEND(NOKEY, DEPENDANT, 0x00, 0x00);
610 else
611 return BLEND(NOKEY, FIX, 0x0, 0x0);
612}
613
614static void tegra_dc_set_blending(struct tegra_dc *dc, struct tegra_dc_blend *blend)
615{
616 unsigned long mask = BIT(DC_N_WINDOWS) - 1;
617
618 while (mask) {
619 int idx = get_topmost_window(blend->z, &mask);
620
621 tegra_dc_writel(dc, WINDOW_A_SELECT << idx,
622 DC_CMD_DISPLAY_WINDOW_HEADER);
623 tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
624 DC_WIN_BLEND_NOKEY);
625 tegra_dc_writel(dc, BLEND(NOKEY, FIX, 0xff, 0xff),
626 DC_WIN_BLEND_1WIN);
627 tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 0),
628 DC_WIN_BLEND_2WIN_X);
629 tegra_dc_writel(dc, blend_2win(idx, mask, blend->flags, 1),
630 DC_WIN_BLEND_2WIN_Y);
631 tegra_dc_writel(dc, blend_3win(idx, mask, blend->flags),
632 DC_WIN_BLEND_3WIN_XY);
633 }
634}
635
636static void tegra_dc_init_csc_defaults(struct tegra_dc_csc *csc)
637{
638 csc->yof = 0x00f0;
639 csc->kyrgb = 0x012a;
640 csc->kur = 0x0000;
641 csc->kvr = 0x0198;
642 csc->kug = 0x039b;
643 csc->kvg = 0x032f;
644 csc->kub = 0x0204;
645 csc->kvb = 0x0000;
646}
647
648static void tegra_dc_set_csc(struct tegra_dc *dc, struct tegra_dc_csc *csc)
649{
650 tegra_dc_writel(dc, csc->yof, DC_WIN_CSC_YOF);
651 tegra_dc_writel(dc, csc->kyrgb, DC_WIN_CSC_KYRGB);
652 tegra_dc_writel(dc, csc->kur, DC_WIN_CSC_KUR);
653 tegra_dc_writel(dc, csc->kvr, DC_WIN_CSC_KVR);
654 tegra_dc_writel(dc, csc->kug, DC_WIN_CSC_KUG);
655 tegra_dc_writel(dc, csc->kvg, DC_WIN_CSC_KVG);
656 tegra_dc_writel(dc, csc->kub, DC_WIN_CSC_KUB);
657 tegra_dc_writel(dc, csc->kvb, DC_WIN_CSC_KVB);
658}
659
660int tegra_dc_update_csc(struct tegra_dc *dc, int win_idx)
661{
662 mutex_lock(&dc->lock);
663
664 if (!dc->enabled) {
665 mutex_unlock(&dc->lock);
666 return -EFAULT;
667 }
668
669 tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
670 DC_CMD_DISPLAY_WINDOW_HEADER);
671
672 tegra_dc_set_csc(dc, &dc->windows[win_idx].csc);
673
674 mutex_unlock(&dc->lock);
675
676 return 0;
677}
678EXPORT_SYMBOL(tegra_dc_update_csc);
679
680static void tegra_dc_init_lut_defaults(struct tegra_dc_lut *lut)
681{
682 int i;
683 for (i = 0; i < 256; i++)
684 lut->r[i] = lut->g[i] = lut->b[i] = (u8)i;
685}
686
687static int tegra_dc_loop_lut(struct tegra_dc *dc,
688 struct tegra_dc_win *win,
689 int(*lambda)(struct tegra_dc *dc, int i, u32 rgb))
690{
691 struct tegra_dc_lut *lut = &win->lut;
692 struct tegra_dc_lut *global_lut = &dc->fb_lut;
693 int i;
694 for (i = 0; i < 256; i++) {
695
696 u32 r = (u32)lut->r[i];
697 u32 g = (u32)lut->g[i];
698 u32 b = (u32)lut->b[i];
699
700 if (!(win->ppflags & TEGRA_WIN_PPFLAG_CP_FBOVERRIDE)) {
701 r = (u32)global_lut->r[r];
702 g = (u32)global_lut->g[g];
703 b = (u32)global_lut->b[b];
704 }
705
706 if (!lambda(dc, i, r | (g<<8) | (b<<16)))
707 return 0;
708 }
709 return 1;
710}
711
712static int tegra_dc_lut_isdefaults_lambda(struct tegra_dc *dc, int i, u32 rgb)
713{
714 if (rgb != (i | (i<<8) | (i<<16)))
715 return 0;
716 return 1;
717}
718
719static int tegra_dc_set_lut_setreg_lambda(struct tegra_dc *dc, int i, u32 rgb)
720{
721 tegra_dc_writel(dc, rgb, DC_WIN_COLOR_PALETTE(i));
722 return 1;
723}
724
725static void tegra_dc_set_lut(struct tegra_dc *dc, struct tegra_dc_win* win)
726{
727 unsigned long val = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
728
729 tegra_dc_loop_lut(dc, win, tegra_dc_set_lut_setreg_lambda);
730
731 if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
732 val |= CP_ENABLE;
733 else
734 val &= ~CP_ENABLE;
735
736 tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
737}
738
739static int tegra_dc_update_winlut(struct tegra_dc *dc, int win_idx, int fbovr)
740{
741 struct tegra_dc_win *win = &dc->windows[win_idx];
742
743 mutex_lock(&dc->lock);
744
745 if (!dc->enabled) {
746 mutex_unlock(&dc->lock);
747 return -EFAULT;
748 }
749
750 if (fbovr > 0)
751 win->ppflags |= TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
752 else if (fbovr == 0)
753 win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_FBOVERRIDE;
754
755 if (!tegra_dc_loop_lut(dc, win, tegra_dc_lut_isdefaults_lambda))
756 win->ppflags |= TEGRA_WIN_PPFLAG_CP_ENABLE;
757 else
758 win->ppflags &= ~TEGRA_WIN_PPFLAG_CP_ENABLE;
759
760 tegra_dc_writel(dc, WINDOW_A_SELECT << win_idx,
761 DC_CMD_DISPLAY_WINDOW_HEADER);
762
763 tegra_dc_set_lut(dc, win);
764
765 mutex_unlock(&dc->lock);
766
767 return 0;
768}
769
770int tegra_dc_update_lut(struct tegra_dc *dc, int win_idx, int fboveride)
771{
772 if (win_idx > -1)
773 return tegra_dc_update_winlut(dc, win_idx, fboveride);
774
775 for (win_idx = 0; win_idx < DC_N_WINDOWS; win_idx++) {
776 int err = tegra_dc_update_winlut(dc, win_idx, fboveride);
777 if (err)
778 return err;
779 }
780
781 return 0;
782}
783EXPORT_SYMBOL(tegra_dc_update_lut);
784
785static void tegra_dc_set_scaling_filter(struct tegra_dc *dc)
786{
787 unsigned i;
788 unsigned v0 = 128;
789 unsigned v1 = 0;
790 /* linear horizontal and vertical filters */
791 for (i = 0; i < 16; i++) {
792 tegra_dc_writel(dc, (v1 << 16) | (v0 << 8),
793 DC_WIN_H_FILTER_P(i));
794
795 tegra_dc_writel(dc, v0,
796 DC_WIN_V_FILTER_P(i));
797 v0 -= 8;
798 v1 += 8;
799 }
800}
801
802static void tegra_dc_set_latency_allowance(struct tegra_dc *dc,
803 struct tegra_dc_win *w)
804{
805 /* windows A, B, C for first and second display */
806 static const enum tegra_la_id la_id_tab[2][3] = {
807 /* first display */
808 { TEGRA_LA_DISPLAY_0A, TEGRA_LA_DISPLAY_0B,
809 TEGRA_LA_DISPLAY_0C },
810 /* second display */
811 { TEGRA_LA_DISPLAY_0AB, TEGRA_LA_DISPLAY_0BB,
812 TEGRA_LA_DISPLAY_0CB },
813 };
814 /* window B V-filter tap for first and second display. */
815 static const enum tegra_la_id vfilter_tab[2] = {
816 TEGRA_LA_DISPLAY_1B, TEGRA_LA_DISPLAY_1BB,
817 };
818 unsigned long bw;
819
820 BUG_ON(dc->ndev->id >= ARRAY_SIZE(la_id_tab));
821 BUG_ON(dc->ndev->id >= ARRAY_SIZE(vfilter_tab));
822 BUG_ON(w->idx >= ARRAY_SIZE(*la_id_tab));
823
824 bw = w->new_bandwidth;
825
826 /* tegra_dc_get_bandwidth() treats V filter windows as double
827 * bandwidth, but LA has a seperate client for V filter */
828 if (w->idx == 1 && win_use_v_filter(w))
829 bw /= 2;
830
831 /* our bandwidth is in bytes/sec, but LA takes MBps.
832 * round up bandwidth to 1MBps */
833 bw = bw / 1000000 + 1;
834
835#ifdef CONFIG_TEGRA_SILICON_PLATFORM
836 tegra_set_latency_allowance(la_id_tab[dc->ndev->id][w->idx], bw);
837 /* if window B, also set the 1B client for the 2-tap V filter. */
838 if (w->idx == 1)
839 tegra_set_latency_allowance(vfilter_tab[dc->ndev->id], bw);
840#endif
841
842 w->bandwidth = w->new_bandwidth;
843}
844
845static unsigned int tegra_dc_windows_is_overlapped(struct tegra_dc_win *a,
846 struct tegra_dc_win *b)
847{
848 if (!WIN_IS_ENABLED(a) || !WIN_IS_ENABLED(b))
849 return 0;
850
851 /* because memory access to load the fifo can overlap, only care
852 * if windows overlap vertically */
853 return ((a->out_y + a->out_h > b->out_y) && (a->out_y <= b->out_y)) ||
854 ((b->out_y + b->out_h > a->out_y) && (b->out_y <= a->out_y));
855}
856
857static unsigned long tegra_dc_find_max_bandwidth(struct tegra_dc_win *wins[],
858 int n)
859{
860 unsigned i;
861 unsigned j;
862 unsigned overlap_count;
863 unsigned max_bw = 0;
864
865 WARN_ONCE(n > 3, "Code assumes at most 3 windows, bandwidth is likely"
866 "inaccurate.\n");
867
868 /* If we had a large number of windows, we would compute adjacency
869 * graph representing 2 window overlaps, find all cliques in the graph,
870 * assign bandwidth to each clique, and then select the clique with
871 * maximum bandwidth. But because we have at most 3 windows,
872 * implementing proper Bron-Kerbosh algorithm would be an overkill,
873 * brute force will suffice.
874 *
875 * Thus: find maximum bandwidth for either single or a pair of windows
876 * and count number of window pair overlaps. If there are three
877 * pairs, all 3 window overlap.
878 */
879
880 overlap_count = 0;
881 for (i = 0; i < n; i++) {
882 unsigned int bw1;
883
884 if (wins[i] == NULL)
885 continue;
886 bw1 = wins[i]->new_bandwidth;
887 if (bw1 > max_bw)
888 /* Single window */
889 max_bw = bw1;
890
891 for (j = i + 1; j < n; j++) {
892 if (wins[j] == NULL)
893 continue;
894 if (tegra_dc_windows_is_overlapped(wins[i], wins[j])) {
895 unsigned int bw2 = wins[j]->new_bandwidth;
896 if (bw1 + bw2 > max_bw)
897 /* Window pair overlaps */
898 max_bw = bw1 + bw2;
899 overlap_count++;
900 }
901 }
902 }
903
904 if (overlap_count == 3)
905 /* All three windows overlap */
906 max_bw = wins[0]->new_bandwidth + wins[1]->new_bandwidth +
907 wins[2]->new_bandwidth;
908
909 return max_bw;
910}
911
912/*
913 * Calculate peak EMC bandwidth for each enabled window =
914 * pixel_clock * win_bpp * (use_v_filter ? 2 : 1)) * H_scale_factor *
915 * (windows_tiling ? 2 : 1)
916 *
917 *
918 * note:
919 * (*) We use 2 tap V filter, so need double BW if use V filter
920 * (*) Tiling mode on T30 and DDR3 requires double BW
921 */
922static unsigned long tegra_dc_calc_win_bandwidth(struct tegra_dc *dc,
923 struct tegra_dc_win *w)
924{
925 unsigned long ret;
926 int tiled_windows_bw_multiplier;
927 unsigned long bpp;
928
929 if (!WIN_IS_ENABLED(w))
930 return 0;
931
932 if (dfixed_trunc(w->w) == 0 || dfixed_trunc(w->h) == 0 ||
933 w->out_w == 0 || w->out_h == 0)
934 return 0;
935
936 tiled_windows_bw_multiplier =
937 tegra_mc_get_tiled_memory_bandwidth_multiplier();
938
939 /* all of tegra's YUV formats(420 and 422) fetch 2 bytes per pixel,
940 * but the size reported by tegra_dc_fmt_bpp for the planar version
941 * is of the luma plane's size only. */
942 bpp = tegra_dc_is_yuv_planar(w->fmt) ?
943 2 * tegra_dc_fmt_bpp(w->fmt) : tegra_dc_fmt_bpp(w->fmt);
944 /* perform calculations with most significant bits of pixel clock
945 * to prevent overflow of long. */
946 ret = (unsigned long)(dc->mode.pclk >> 16) *
947 bpp / 8 *
948 (win_use_v_filter(w) ? 2 : 1) * dfixed_trunc(w->w) / w->out_w *
949 (WIN_IS_TILED(w) ? tiled_windows_bw_multiplier : 1);
950
951/*
952 * Assuming 48% efficiency: i.e. if we calculate we need 70MBps, we
953 * will request 147MBps from EMC.
954 */
955 ret = ret * 2 + ret / 10;
956
957 /* if overflowed */
958 if (ret > (1UL << 31))
959 return ULONG_MAX;
960
961 return ret << 16; /* restore the scaling we did above */
962}
963
964static unsigned long tegra_dc_get_bandwidth(
965 struct tegra_dc_win *windows[], int n)
966{
967 int i;
968
969 BUG_ON(n > DC_N_WINDOWS);
970
971 /* emc rate and latency allowance both need to know per window
972 * bandwidths */
973 for (i = 0; i < n; i++) {
974 struct tegra_dc_win *w = windows[i];
975 if (w)
976 w->new_bandwidth = tegra_dc_calc_win_bandwidth(w->dc, w);
977 }
978
979 return tegra_dc_find_max_bandwidth(windows, n);
980}
981
982/* to save power, call when display memory clients would be idle */
983static void tegra_dc_clear_bandwidth(struct tegra_dc *dc)
984{
985 if (tegra_is_clk_enabled(dc->emc_clk))
986 clk_disable(dc->emc_clk);
987 dc->emc_clk_rate = 0;
988}
989
990static void tegra_dc_program_bandwidth(struct tegra_dc *dc)
991{
992 unsigned i;
993
994 if (dc->emc_clk_rate != dc->new_emc_clk_rate) {
995 /* going from 0 to non-zero */
996 if (!dc->emc_clk_rate && !tegra_is_clk_enabled(dc->emc_clk))
997 clk_enable(dc->emc_clk);
998
999 dc->emc_clk_rate = dc->new_emc_clk_rate;
1000 clk_set_rate(dc->emc_clk, dc->emc_clk_rate);
1001
1002 if (!dc->new_emc_clk_rate) /* going from non-zero to 0 */
1003 clk_disable(dc->emc_clk);
1004 }
1005
1006 for (i = 0; i < DC_N_WINDOWS; i++) {
1007 struct tegra_dc_win *w = &dc->windows[i];
1008 if (w->bandwidth != w->new_bandwidth && w->new_bandwidth != 0)
1009 tegra_dc_set_latency_allowance(dc, w);
1010 }
1011}
1012
1013static int tegra_dc_set_dynamic_emc(struct tegra_dc_win *windows[], int n)
1014{
1015 unsigned long new_rate;
1016 struct tegra_dc *dc;
1017
1018 if (!use_dynamic_emc)
1019 return 0;
1020
1021 dc = windows[0]->dc;
1022
1023 /* calculate the new rate based on this POST */
1024 new_rate = tegra_dc_get_bandwidth(windows, n);
1025 new_rate = EMC_BW_TO_FREQ(new_rate);
1026
1027 if (tegra_dc_has_multiple_dc())
1028 new_rate = ULONG_MAX;
1029
1030 dc->new_emc_clk_rate = new_rate;
1031
1032 return 0;
1033}
1034
1035static inline u32 compute_dda_inc(fixed20_12 in, unsigned out_int,
1036 bool v, unsigned Bpp)
1037{
1038 /*
1039 * min(round((prescaled_size_in_pixels - 1) * 0x1000 /
1040 * (post_scaled_size_in_pixels - 1)), MAX)
1041 * Where the value of MAX is as follows:
1042 * For V_DDA_INCREMENT: 15.0 (0xF000)
1043 * For H_DDA_INCREMENT: 4.0 (0x4000) for 4 Bytes/pix formats.
1044 * 8.0 (0x8000) for 2 Bytes/pix formats.
1045 */
1046
1047 fixed20_12 out = dfixed_init(out_int);
1048 u32 dda_inc;
1049 int max;
1050
1051 if (v) {
1052 max = 15;
1053 } else {
1054 switch (Bpp) {
1055 default:
1056 WARN_ON_ONCE(1);
1057 /* fallthrough */
1058 case 4:
1059 max = 4;
1060 break;
1061 case 2:
1062 max = 8;
1063 break;
1064 }
1065 }
1066
1067 out.full = max_t(u32, out.full - dfixed_const(1), dfixed_const(1));
1068 in.full -= dfixed_const(1);
1069
1070 dda_inc = dfixed_div(in, out);
1071
1072 dda_inc = min_t(u32, dda_inc, dfixed_const(max));
1073
1074 return dda_inc;
1075}
1076
1077static inline u32 compute_initial_dda(fixed20_12 in)
1078{
1079 return dfixed_frac(in);
1080}
1081
1082/* does not support updating windows on multiple dcs in one call */
1083int tegra_dc_update_windows(struct tegra_dc_win *windows[], int n)
1084{
1085 struct tegra_dc *dc;
1086 unsigned long update_mask = GENERAL_ACT_REQ;
1087 unsigned long val;
1088 bool update_blend = false;
1089 int i;
1090
1091 dc = windows[0]->dc;
1092
1093 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
1094 /* Acquire one_shot_lock to avoid race condition between
1095 * cancellation of old delayed work and schedule of new
1096 * delayed work. */
1097 mutex_lock(&dc->one_shot_lock);
1098 cancel_delayed_work_sync(&dc->one_shot_work);
1099 }
1100 mutex_lock(&dc->lock);
1101
1102 if (!dc->enabled) {
1103 mutex_unlock(&dc->lock);
1104 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
1105 mutex_unlock(&dc->one_shot_lock);
1106 return -EFAULT;
1107 }
1108
1109 if (no_vsync)
1110 tegra_dc_writel(dc, WRITE_MUX_ACTIVE | READ_MUX_ACTIVE, DC_CMD_STATE_ACCESS);
1111 else
1112 tegra_dc_writel(dc, WRITE_MUX_ASSEMBLY | READ_MUX_ASSEMBLY, DC_CMD_STATE_ACCESS);
1113
1114 for (i = 0; i < DC_N_WINDOWS; i++) {
1115 tegra_dc_writel(dc, WINDOW_A_SELECT << i,
1116 DC_CMD_DISPLAY_WINDOW_HEADER);
1117 tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
1118 if (!no_vsync)
1119 update_mask |= WIN_A_ACT_REQ << i;
1120 }
1121
1122 for (i = 0; i < n; i++) {
1123 struct tegra_dc_win *win = windows[i];
1124 unsigned h_dda;
1125 unsigned v_dda;
1126 fixed20_12 h_offset, v_offset;
1127 bool invert_h = (win->flags & TEGRA_WIN_FLAG_INVERT_H) != 0;
1128 bool invert_v = (win->flags & TEGRA_WIN_FLAG_INVERT_V) != 0;
1129 bool yuvp = tegra_dc_is_yuv_planar(win->fmt);
1130 unsigned Bpp = tegra_dc_fmt_bpp(win->fmt) / 8;
1131 /* Bytes per pixel of bandwidth, used for dda_inc calculation */
1132 unsigned Bpp_bw = Bpp * (yuvp ? 2 : 1);
1133 const bool filter_h = win_use_h_filter(win);
1134 const bool filter_v = win_use_v_filter(win);
1135
1136 if (win->z != dc->blend.z[win->idx]) {
1137 dc->blend.z[win->idx] = win->z;
1138 update_blend = true;
1139 }
1140 if ((win->flags & TEGRA_WIN_BLEND_FLAGS_MASK) !=
1141 dc->blend.flags[win->idx]) {
1142 dc->blend.flags[win->idx] =
1143 win->flags & TEGRA_WIN_BLEND_FLAGS_MASK;
1144 update_blend = true;
1145 }
1146
1147 tegra_dc_writel(dc, WINDOW_A_SELECT << win->idx,
1148 DC_CMD_DISPLAY_WINDOW_HEADER);
1149
1150 if (!no_vsync)
1151 update_mask |= WIN_A_ACT_REQ << win->idx;
1152
1153 if (!WIN_IS_ENABLED(win)) {
1154 tegra_dc_writel(dc, 0, DC_WIN_WIN_OPTIONS);
1155 continue;
1156 }
1157
1158 tegra_dc_writel(dc, win->fmt, DC_WIN_COLOR_DEPTH);
1159 tegra_dc_writel(dc, 0, DC_WIN_BYTE_SWAP);
1160
1161 tegra_dc_writel(dc,
1162 V_POSITION(win->out_y) | H_POSITION(win->out_x),
1163 DC_WIN_POSITION);
1164 tegra_dc_writel(dc,
1165 V_SIZE(win->out_h) | H_SIZE(win->out_w),
1166 DC_WIN_SIZE);
1167 tegra_dc_writel(dc,
1168 V_PRESCALED_SIZE(dfixed_trunc(win->h)) |
1169 H_PRESCALED_SIZE(dfixed_trunc(win->w) * Bpp),
1170 DC_WIN_PRESCALED_SIZE);
1171
1172 h_dda = compute_dda_inc(win->w, win->out_w, false, Bpp_bw);
1173 v_dda = compute_dda_inc(win->h, win->out_h, true, Bpp_bw);
1174 tegra_dc_writel(dc, V_DDA_INC(v_dda) | H_DDA_INC(h_dda),
1175 DC_WIN_DDA_INCREMENT);
1176 h_dda = compute_initial_dda(win->x);
1177 v_dda = compute_initial_dda(win->y);
1178 tegra_dc_writel(dc, h_dda, DC_WIN_H_INITIAL_DDA);
1179 tegra_dc_writel(dc, v_dda, DC_WIN_V_INITIAL_DDA);
1180
1181 tegra_dc_writel(dc, 0, DC_WIN_BUF_STRIDE);
1182 tegra_dc_writel(dc, 0, DC_WIN_UV_BUF_STRIDE);
1183 tegra_dc_writel(dc,
1184 (unsigned long)win->phys_addr,
1185 DC_WINBUF_START_ADDR);
1186
1187 if (!yuvp) {
1188 tegra_dc_writel(dc, win->stride, DC_WIN_LINE_STRIDE);
1189 } else {
1190 tegra_dc_writel(dc,
1191 (unsigned long)win->phys_addr_u,
1192 DC_WINBUF_START_ADDR_U);
1193 tegra_dc_writel(dc,
1194 (unsigned long)win->phys_addr_v,
1195 DC_WINBUF_START_ADDR_V);
1196 tegra_dc_writel(dc,
1197 LINE_STRIDE(win->stride) |
1198 UV_LINE_STRIDE(win->stride_uv),
1199 DC_WIN_LINE_STRIDE);
1200 }
1201
1202 h_offset = win->x;
1203 if (invert_h) {
1204 h_offset.full += win->w.full - dfixed_const(1);
1205 }
1206
1207 v_offset = win->y;
1208 if (invert_v) {
1209 v_offset.full += win->h.full - dfixed_const(1);
1210 }
1211
1212 tegra_dc_writel(dc, dfixed_trunc(h_offset) * Bpp,
1213 DC_WINBUF_ADDR_H_OFFSET);
1214 tegra_dc_writel(dc, dfixed_trunc(v_offset),
1215 DC_WINBUF_ADDR_V_OFFSET);
1216
1217 if (WIN_IS_TILED(win))
1218 tegra_dc_writel(dc,
1219 DC_WIN_BUFFER_ADDR_MODE_TILE |
1220 DC_WIN_BUFFER_ADDR_MODE_TILE_UV,
1221 DC_WIN_BUFFER_ADDR_MODE);
1222 else
1223 tegra_dc_writel(dc,
1224 DC_WIN_BUFFER_ADDR_MODE_LINEAR |
1225 DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV,
1226 DC_WIN_BUFFER_ADDR_MODE);
1227
1228 val = WIN_ENABLE;
1229 if (yuvp)
1230 val |= CSC_ENABLE;
1231 else if (tegra_dc_fmt_bpp(win->fmt) < 24)
1232 val |= COLOR_EXPAND;
1233
1234 if (win->ppflags & TEGRA_WIN_PPFLAG_CP_ENABLE)
1235 val |= CP_ENABLE;
1236
1237 if (filter_h)
1238 val |= H_FILTER_ENABLE;
1239 if (filter_v)
1240 val |= V_FILTER_ENABLE;
1241
1242 if (invert_h)
1243 val |= H_DIRECTION_DECREMENT;
1244 if (invert_v)
1245 val |= V_DIRECTION_DECREMENT;
1246
1247 tegra_dc_writel(dc, val, DC_WIN_WIN_OPTIONS);
1248
1249 win->dirty = no_vsync ? 0 : 1;
1250
1251 dev_dbg(&dc->ndev->dev, "%s():idx=%d z=%d x=%d y=%d w=%d h=%d "
1252 "out_x=%u out_y=%u out_w=%u out_h=%u "
1253 "fmt=%d yuvp=%d Bpp=%u filter_h=%d filter_v=%d",
1254 __func__, win->idx, win->z,
1255 dfixed_trunc(win->x), dfixed_trunc(win->y),
1256 dfixed_trunc(win->w), dfixed_trunc(win->h),
1257 win->out_x, win->out_y, win->out_w, win->out_h,
1258 win->fmt, yuvp, Bpp, filter_h, filter_v);
1259 }
1260
1261 if (update_blend) {
1262 tegra_dc_set_blending(dc, &dc->blend);
1263 for (i = 0; i < DC_N_WINDOWS; i++) {
1264 if (!no_vsync)
1265 dc->windows[i].dirty = 1;
1266 update_mask |= WIN_A_ACT_REQ << i;
1267 }
1268 }
1269
1270 tegra_dc_set_dynamic_emc(windows, n);
1271
1272 tegra_dc_writel(dc, update_mask << 8, DC_CMD_STATE_CONTROL);
1273
1274 tegra_dc_writel(dc, FRAME_END_INT | V_BLANK_INT, DC_CMD_INT_STATUS);
1275 if (!no_vsync) {
1276 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
1277 val |= (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
1278 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
1279 } else {
1280 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
1281 val &= ~(FRAME_END_INT | V_BLANK_INT | ALL_UF_INT);
1282 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
1283 }
1284
1285 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
1286 schedule_delayed_work(&dc->one_shot_work,
1287 msecs_to_jiffies(dc->one_shot_delay_ms));
1288
1289 /* update EMC clock if calculated bandwidth has changed */
1290 tegra_dc_program_bandwidth(dc);
1291
1292 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
1293 update_mask |= NC_HOST_TRIG;
1294
1295 tegra_dc_writel(dc, update_mask, DC_CMD_STATE_CONTROL);
1296
1297 mutex_unlock(&dc->lock);
1298 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
1299 mutex_unlock(&dc->one_shot_lock);
1300
1301 return 0;
1302}
1303EXPORT_SYMBOL(tegra_dc_update_windows);
1304
1305u32 tegra_dc_get_syncpt_id(const struct tegra_dc *dc, int i)
1306{
1307 return dc->syncpt[i].id;
1308}
1309EXPORT_SYMBOL(tegra_dc_get_syncpt_id);
1310
1311u32 tegra_dc_incr_syncpt_max(struct tegra_dc *dc, int i)
1312{
1313 u32 max;
1314
1315 mutex_lock(&dc->lock);
1316 max = nvhost_syncpt_incr_max(&nvhost_get_host(dc->ndev)->syncpt,
1317 dc->syncpt[i].id, ((dc->enabled) ? 1 : 0));
1318 dc->syncpt[i].max = max;
1319 mutex_unlock(&dc->lock);
1320
1321 return max;
1322}
1323
1324void tegra_dc_incr_syncpt_min(struct tegra_dc *dc, int i, u32 val)
1325{
1326 mutex_lock(&dc->lock);
1327 if ( dc->enabled )
1328 while (dc->syncpt[i].min < val) {
1329 dc->syncpt[i].min++;
1330 nvhost_syncpt_cpu_incr(
1331 &nvhost_get_host(dc->ndev)->syncpt,
1332 dc->syncpt[i].id);
1333 }
1334 mutex_unlock(&dc->lock);
1335}
1336
1337static bool tegra_dc_windows_are_clean(struct tegra_dc_win *windows[],
1338 int n)
1339{
1340 int i;
1341
1342 for (i = 0; i < n; i++) {
1343 if (windows[i]->dirty)
1344 return false;
1345 }
1346
1347 return true;
1348}
1349
1350/* does not support syncing windows on multiple dcs in one call */
1351int tegra_dc_sync_windows(struct tegra_dc_win *windows[], int n)
1352{
1353 if (n < 1 || n > DC_N_WINDOWS)
1354 return -EINVAL;
1355
1356 if (!windows[0]->dc->enabled)
1357 return -EFAULT;
1358
1359#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
1360 /* Don't want to timeout on simulator */
1361 return wait_event_interruptible(windows[0]->dc->wq,
1362 tegra_dc_windows_are_clean(windows, n));
1363#else
1364 return wait_event_interruptible_timeout(windows[0]->dc->wq,
1365 tegra_dc_windows_are_clean(windows, n),
1366 HZ);
1367#endif
1368}
1369EXPORT_SYMBOL(tegra_dc_sync_windows);
1370
1371static unsigned long tegra_dc_clk_get_rate(struct tegra_dc *dc)
1372{
1373#ifdef CONFIG_TEGRA_SILICON_PLATFORM
1374 return clk_get_rate(dc->clk);
1375#else
1376 return 27000000;
1377#endif
1378}
1379
1380static unsigned long tegra_dc_pclk_round_rate(struct tegra_dc *dc, int pclk)
1381{
1382 unsigned long rate;
1383 unsigned long div;
1384
1385 rate = tegra_dc_clk_get_rate(dc);
1386
1387 div = DIV_ROUND_CLOSEST(rate * 2, pclk);
1388
1389 if (div < 2)
1390 return 0;
1391
1392 return rate * 2 / div;
1393}
1394
1395static unsigned long tegra_dc_pclk_predict_rate(struct clk *parent, int pclk)
1396{
1397 unsigned long rate;
1398 unsigned long div;
1399
1400 rate = clk_get_rate(parent);
1401
1402 div = DIV_ROUND_CLOSEST(rate * 2, pclk);
1403
1404 if (div < 2)
1405 return 0;
1406
1407 return rate * 2 / div;
1408}
1409
1410void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk)
1411{
1412 int pclk;
1413
1414 if (dc->out->type == TEGRA_DC_OUT_RGB) {
1415 unsigned long rate;
1416 struct clk *parent_clk =
1417 clk_get_sys(NULL, dc->out->parent_clk ? : "pll_p");
1418
1419 if (dc->out->parent_clk_backup &&
1420 (parent_clk == clk_get_sys(NULL, "pll_p"))) {
1421 rate = tegra_dc_pclk_predict_rate(
1422 parent_clk, dc->mode.pclk);
1423 /* use pll_d as last resort */
1424 if (rate < (dc->mode.pclk / 100 * 99) ||
1425 rate > (dc->mode.pclk / 100 * 109))
1426 parent_clk = clk_get_sys(
1427 NULL, dc->out->parent_clk_backup);
1428 }
1429
1430 if (clk_get_parent(clk) != parent_clk)
1431 clk_set_parent(clk, parent_clk);
1432
1433 if (parent_clk != clk_get_sys(NULL, "pll_p")) {
1434 struct clk *base_clk = clk_get_parent(parent_clk);
1435
1436 /* Assuming either pll_d or pll_d2 is used */
1437 rate = dc->mode.pclk * 2;
1438
1439 if (rate != clk_get_rate(base_clk))
1440 clk_set_rate(base_clk, rate);
1441 }
1442 }
1443
1444 if (dc->out->type == TEGRA_DC_OUT_HDMI) {
1445 unsigned long rate;
1446 struct clk *parent_clk =
1447 clk_get_sys(NULL, dc->out->parent_clk ? : "pll_d_out0");
1448 struct clk *base_clk = clk_get_parent(parent_clk);
1449
1450 /*
1451 * Providing dynamic frequency rate setting for T20/T30 HDMI.
1452 * The required rate needs to be setup at 4x multiplier,
1453 * as out0 is 1/2 of the actual PLL output.
1454 */
1455
1456 rate = dc->mode.pclk * 4;
1457 if (rate != clk_get_rate(base_clk))
1458 clk_set_rate(base_clk, rate);
1459
1460 if (clk_get_parent(clk) != parent_clk)
1461 clk_set_parent(clk, parent_clk);
1462 }
1463
1464 if (dc->out->type == TEGRA_DC_OUT_DSI) {
1465 unsigned long rate;
1466 struct clk *parent_clk;
1467 struct clk *base_clk;
1468
1469 if (clk == dc->clk) {
1470 parent_clk = clk_get_sys(NULL,
1471 dc->out->parent_clk ? : "pll_d_out0");
1472 base_clk = clk_get_parent(parent_clk);
1473 tegra_clk_cfg_ex(base_clk,
1474 TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
1475 } else {
1476 if (dc->pdata->default_out->dsi->dsi_instance) {
1477 parent_clk = clk_get_sys(NULL,
1478 dc->out->parent_clk ? : "pll_d2_out0");
1479 base_clk = clk_get_parent(parent_clk);
1480 tegra_clk_cfg_ex(base_clk,
1481 TEGRA_CLK_PLLD_CSI_OUT_ENB, 1);
1482 } else {
1483 parent_clk = clk_get_sys(NULL,
1484 dc->out->parent_clk ? : "pll_d_out0");
1485 base_clk = clk_get_parent(parent_clk);
1486 tegra_clk_cfg_ex(base_clk,
1487 TEGRA_CLK_PLLD_DSI_OUT_ENB, 1);
1488 }
1489 }
1490
1491 rate = dc->mode.pclk * dc->shift_clk_div * 2;
1492 if (rate != clk_get_rate(base_clk))
1493 clk_set_rate(base_clk, rate);
1494
1495 if (clk_get_parent(clk) != parent_clk)
1496 clk_set_parent(clk, parent_clk);
1497 }
1498
1499 pclk = tegra_dc_pclk_round_rate(dc, dc->mode.pclk);
1500 tegra_dvfs_set_rate(clk, pclk);
1501}
1502
1503/* return non-zero if constraint is violated */
1504static int calc_h_ref_to_sync(const struct tegra_dc_mode *mode, int *href)
1505{
1506 long a, b;
1507
1508 /* Constraint 5: H_REF_TO_SYNC >= 0 */
1509 a = 0;
1510
1511 /* Constraint 6: H_FRONT_PORT >= (H_REF_TO_SYNC + 1) */
1512 b = mode->h_front_porch - 1;
1513
1514 /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11 */
1515 if (a + mode->h_sync_width + mode->h_back_porch <= 11)
1516 a = 1 + 11 - mode->h_sync_width - mode->h_back_porch;
1517 /* check Constraint 1 and 6 */
1518 if (a > b)
1519 return 1;
1520
1521 /* Constraint 4: H_SYNC_WIDTH >= 1 */
1522 if (mode->h_sync_width < 1)
1523 return 4;
1524
1525 /* Constraint 7: H_DISP_ACTIVE >= 16 */
1526 if (mode->h_active < 16)
1527 return 7;
1528
1529 if (href) {
1530 if (b > a && a % 2)
1531 *href = a + 1; /* use smallest even value */
1532 else
1533 *href = a; /* even or only possible value */
1534 }
1535
1536 return 0;
1537}
1538
1539static int calc_v_ref_to_sync(const struct tegra_dc_mode *mode, int *vref)
1540{
1541 long a;
1542 a = 1; /* Constraint 5: V_REF_TO_SYNC >= 1 */
1543
1544 /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1 */
1545 if (a + mode->v_sync_width + mode->v_back_porch <= 1)
1546 a = 1 + 1 - mode->v_sync_width - mode->v_back_porch;
1547
1548 /* Constraint 6 */
1549 if (mode->v_front_porch < a + 1)
1550 a = mode->v_front_porch - 1;
1551
1552 /* Constraint 4: V_SYNC_WIDTH >= 1 */
1553 if (mode->v_sync_width < 1)
1554 return 4;
1555
1556 /* Constraint 7: V_DISP_ACTIVE >= 16 */
1557 if (mode->v_active < 16)
1558 return 7;
1559
1560 if (vref)
1561 *vref = a;
1562 return 0;
1563}
1564
1565static int calc_ref_to_sync(struct tegra_dc_mode *mode)
1566{
1567 int ret;
1568 ret = calc_h_ref_to_sync(mode, &mode->h_ref_to_sync);
1569 if (ret)
1570 return ret;
1571 ret = calc_v_ref_to_sync(mode, &mode->v_ref_to_sync);
1572 if (ret)
1573 return ret;
1574
1575 return 0;
1576}
1577
1578static bool check_ref_to_sync(struct tegra_dc_mode *mode)
1579{
1580 /* Constraint 1: H_REF_TO_SYNC + H_SYNC_WIDTH + H_BACK_PORCH > 11. */
1581 if (mode->h_ref_to_sync + mode->h_sync_width + mode->h_back_porch <= 11)
1582 return false;
1583
1584 /* Constraint 2: V_REF_TO_SYNC + V_SYNC_WIDTH + V_BACK_PORCH > 1. */
1585 if (mode->v_ref_to_sync + mode->v_sync_width + mode->v_back_porch <= 1)
1586 return false;
1587
1588 /* Constraint 3: V_FRONT_PORCH + V_SYNC_WIDTH + V_BACK_PORCH > 1
1589 * (vertical blank). */
1590 if (mode->v_front_porch + mode->v_sync_width + mode->v_back_porch <= 1)
1591 return false;
1592
1593 /* Constraint 4: V_SYNC_WIDTH >= 1; H_SYNC_WIDTH >= 1. */
1594 if (mode->v_sync_width < 1 || mode->h_sync_width < 1)
1595 return false;
1596
1597 /* Constraint 5: V_REF_TO_SYNC >= 1; H_REF_TO_SYNC >= 0. */
1598 if (mode->v_ref_to_sync < 1 || mode->h_ref_to_sync < 0)
1599 return false;
1600
1601 /* Constraint 6: V_FRONT_PORT >= (V_REF_TO_SYNC + 1);
1602 * H_FRONT_PORT >= (H_REF_TO_SYNC + 1). */
1603 if (mode->v_front_porch < mode->v_ref_to_sync + 1 ||
1604 mode->h_front_porch < mode->h_ref_to_sync + 1)
1605 return false;
1606
1607 /* Constraint 7: H_DISP_ACTIVE >= 16; V_DISP_ACTIVE >= 16. */
1608 if (mode->h_active < 16 || mode->v_active < 16)
1609 return false;
1610
1611 return true;
1612}
1613
1614#ifdef DEBUG
1615/* return in 1000ths of a Hertz */
1616static int calc_refresh(const struct tegra_dc_mode *m)
1617{
1618 long h_total, v_total, refresh;
1619 h_total = m->h_active + m->h_front_porch + m->h_back_porch +
1620 m->h_sync_width;
1621 v_total = m->v_active + m->v_front_porch + m->v_back_porch +
1622 m->v_sync_width;
1623 refresh = m->pclk / h_total;
1624 refresh *= 1000;
1625 refresh /= v_total;
1626 return refresh;
1627}
1628
1629static void print_mode(struct tegra_dc *dc,
1630 const struct tegra_dc_mode *mode, const char *note)
1631{
1632 if (mode) {
1633 int refresh = calc_refresh(dc, mode);
1634 dev_info(&dc->ndev->dev, "%s():MODE:%dx%d@%d.%03uHz pclk=%d\n",
1635 note ? note : "",
1636 mode->h_active, mode->v_active,
1637 refresh / 1000, refresh % 1000,
1638 mode->pclk);
1639 }
1640}
1641#else /* !DEBUG */
1642static inline void print_mode(struct tegra_dc *dc,
1643 const struct tegra_dc_mode *mode, const char *note) { }
1644#endif /* DEBUG */
1645
1646static inline void enable_dc_irq(unsigned int irq)
1647{
1648#ifndef CONFIG_TEGRA_FPGA_PLATFORM
1649 enable_irq(irq);
1650#else
1651 /* Always disable DC interrupts on FPGA. */
1652 disable_irq(irq);
1653#endif
1654}
1655
1656static inline void disable_dc_irq(unsigned int irq)
1657{
1658 disable_irq(irq);
1659}
1660
1661static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode)
1662{
1663 unsigned long val;
1664 unsigned long rate;
1665 unsigned long div;
1666 unsigned long pclk;
1667
1668 print_mode(dc, mode, __func__);
1669
1670 /* use default EMC rate when switching modes */
1671 dc->new_emc_clk_rate = tegra_dc_get_default_emc_clk_rate(dc);
1672 tegra_dc_program_bandwidth(dc);
1673
1674 tegra_dc_writel(dc, 0x0, DC_DISP_DISP_TIMING_OPTIONS);
1675 tegra_dc_writel(dc, mode->h_ref_to_sync | (mode->v_ref_to_sync << 16),
1676 DC_DISP_REF_TO_SYNC);
1677 tegra_dc_writel(dc, mode->h_sync_width | (mode->v_sync_width << 16),
1678 DC_DISP_SYNC_WIDTH);
1679 tegra_dc_writel(dc, mode->h_back_porch | (mode->v_back_porch << 16),
1680 DC_DISP_BACK_PORCH);
1681 tegra_dc_writel(dc, mode->h_active | (mode->v_active << 16),
1682 DC_DISP_DISP_ACTIVE);
1683 tegra_dc_writel(dc, mode->h_front_porch | (mode->v_front_porch << 16),
1684 DC_DISP_FRONT_PORCH);
1685
1686 tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
1687 DC_DISP_DATA_ENABLE_OPTIONS);
1688
1689 /* TODO: MIPI/CRT/HDMI clock cals */
1690
1691 val = DISP_DATA_FORMAT_DF1P1C;
1692
1693 if (dc->out->align == TEGRA_DC_ALIGN_MSB)
1694 val |= DISP_DATA_ALIGNMENT_MSB;
1695 else
1696 val |= DISP_DATA_ALIGNMENT_LSB;
1697
1698 if (dc->out->order == TEGRA_DC_ORDER_RED_BLUE)
1699 val |= DISP_DATA_ORDER_RED_BLUE;
1700 else
1701 val |= DISP_DATA_ORDER_BLUE_RED;
1702
1703 tegra_dc_writel(dc, val, DC_DISP_DISP_INTERFACE_CONTROL);
1704
1705 rate = tegra_dc_clk_get_rate(dc);
1706
1707 pclk = tegra_dc_pclk_round_rate(dc, mode->pclk);
1708 if (pclk < (mode->pclk / 100 * 99) ||
1709 pclk > (mode->pclk / 100 * 109)) {
1710 dev_err(&dc->ndev->dev,
1711 "can't divide %ld clock to %d -1/+9%% %ld %d %d\n",
1712 rate, mode->pclk,
1713 pclk, (mode->pclk / 100 * 99),
1714 (mode->pclk / 100 * 109));
1715 return -EINVAL;
1716 }
1717
1718 div = (rate * 2 / pclk) - 2;
1719
1720 tegra_dc_writel(dc, 0x00010001,
1721 DC_DISP_SHIFT_CLOCK_OPTIONS);
1722 tegra_dc_writel(dc, PIXEL_CLK_DIVIDER_PCD1 | SHIFT_CLK_DIVIDER(div),
1723 DC_DISP_DISP_CLOCK_CONTROL);
1724
1725#ifdef CONFIG_SWITCH
1726 switch_set_state(&dc->modeset_switch,
1727 (mode->h_active << 16) | mode->v_active);
1728#endif
1729
1730 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
1731 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
1732
1733 return 0;
1734}
1735
1736
1737int tegra_dc_set_mode(struct tegra_dc *dc, const struct tegra_dc_mode *mode)
1738{
1739 memcpy(&dc->mode, mode, sizeof(dc->mode));
1740
1741 print_mode(dc, mode, __func__);
1742
1743 return 0;
1744}
1745EXPORT_SYMBOL(tegra_dc_set_mode);
1746
1747int tegra_dc_set_fb_mode(struct tegra_dc *dc,
1748 const struct fb_videomode *fbmode, bool stereo_mode)
1749{
1750 struct tegra_dc_mode mode;
1751
1752 if (!fbmode->pixclock)
1753 return -EINVAL;
1754
1755 mode.pclk = PICOS2KHZ(fbmode->pixclock) * 1000;
1756 mode.h_sync_width = fbmode->hsync_len;
1757 mode.v_sync_width = fbmode->vsync_len;
1758 mode.h_back_porch = fbmode->left_margin;
1759 mode.v_back_porch = fbmode->upper_margin;
1760 mode.h_active = fbmode->xres;
1761 mode.v_active = fbmode->yres;
1762 mode.h_front_porch = fbmode->right_margin;
1763 mode.v_front_porch = fbmode->lower_margin;
1764 mode.stereo_mode = stereo_mode;
1765 if (dc->out->type == TEGRA_DC_OUT_HDMI) {
1766 /* HDMI controller requires h_ref=1, v_ref=1 */
1767 mode.h_ref_to_sync = 1;
1768 mode.v_ref_to_sync = 1;
1769 } else {
1770 calc_ref_to_sync(&mode);
1771 }
1772 if (!check_ref_to_sync(&mode)) {
1773 dev_err(&dc->ndev->dev,
1774 "Display timing doesn't meet restrictions.\n");
1775 return -EINVAL;
1776 }
1777 dev_info(&dc->ndev->dev, "Using mode %dx%d pclk=%d href=%d vref=%d\n",
1778 mode.h_active, mode.v_active, mode.pclk,
1779 mode.h_ref_to_sync, mode.v_ref_to_sync
1780 );
1781
1782#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
1783 /* Double the pixel clock and update v_active only for frame packed mode */
1784 if (mode.stereo_mode) {
1785 mode.pclk *= 2;
1786 /* total v_active = yres*2 + activespace */
1787 mode.v_active = fbmode->yres*2 +
1788 fbmode->vsync_len +
1789 fbmode->upper_margin +
1790 fbmode->lower_margin;
1791 }
1792#endif
1793
1794 mode.flags = 0;
1795
1796 if (!(fbmode->sync & FB_SYNC_HOR_HIGH_ACT))
1797 mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
1798
1799 if (!(fbmode->sync & FB_SYNC_VERT_HIGH_ACT))
1800 mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
1801
1802 return tegra_dc_set_mode(dc, &mode);
1803}
1804EXPORT_SYMBOL(tegra_dc_set_fb_mode);
1805
1806void
1807tegra_dc_config_pwm(struct tegra_dc *dc, struct tegra_dc_pwm_params *cfg)
1808{
1809 unsigned int ctrl;
1810 unsigned long out_sel;
1811 unsigned long cmd_state;
1812
1813 mutex_lock(&dc->lock);
1814 if (!dc->enabled) {
1815 mutex_unlock(&dc->lock);
1816 return;
1817 }
1818
1819 ctrl = ((cfg->period << PM_PERIOD_SHIFT) |
1820 (cfg->clk_div << PM_CLK_DIVIDER_SHIFT) |
1821 cfg->clk_select);
1822
1823 /* The new value should be effected immediately */
1824 cmd_state = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
1825 tegra_dc_writel(dc, (cmd_state | (1 << 2)), DC_CMD_STATE_ACCESS);
1826
1827 if (cfg->switch_to_sfio && cfg->gpio_conf_to_sfio)
1828 cfg->switch_to_sfio(cfg->gpio_conf_to_sfio);
1829 else
1830 dev_err(&dc->ndev->dev, "Error: Need gpio_conf_to_sfio\n");
1831
1832 switch (cfg->which_pwm) {
1833 case TEGRA_PWM_PM0:
1834 /* Select the LM0 on PM0 */
1835 out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5);
1836 out_sel &= ~(7 << 0);
1837 out_sel |= (3 << 0);
1838 tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5);
1839 tegra_dc_writel(dc, ctrl, DC_COM_PM0_CONTROL);
1840 tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM0_DUTY_CYCLE);
1841 break;
1842 case TEGRA_PWM_PM1:
1843 /* Select the LM1 on PM1 */
1844 out_sel = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT5);
1845 out_sel &= ~(7 << 4);
1846 out_sel |= (3 << 4);
1847 tegra_dc_writel(dc, out_sel, DC_COM_PIN_OUTPUT_SELECT5);
1848 tegra_dc_writel(dc, ctrl, DC_COM_PM1_CONTROL);
1849 tegra_dc_writel(dc, cfg->duty_cycle, DC_COM_PM1_DUTY_CYCLE);
1850 break;
1851 default:
1852 dev_err(&dc->ndev->dev, "Error: Need which_pwm\n");
1853 break;
1854 }
1855 tegra_dc_writel(dc, cmd_state, DC_CMD_STATE_ACCESS);
1856 mutex_unlock(&dc->lock);
1857}
1858EXPORT_SYMBOL(tegra_dc_config_pwm);
1859
1860void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
1861 const struct tegra_dc_out_pin *pins,
1862 const unsigned int n_pins)
1863{
1864 unsigned int i;
1865
1866 int name;
1867 int pol;
1868
1869 u32 pol1, pol3;
1870
1871 u32 set1, unset1;
1872 u32 set3, unset3;
1873
1874 set1 = set3 = unset1 = unset3 = 0;
1875
1876 for (i = 0; i < n_pins; i++) {
1877 name = (pins + i)->name;
1878 pol = (pins + i)->pol;
1879
1880 /* set polarity by name */
1881 switch (name) {
1882 case TEGRA_DC_OUT_PIN_DATA_ENABLE:
1883 if (pol == TEGRA_DC_OUT_PIN_POL_LOW)
1884 set3 |= LSPI_OUTPUT_POLARITY_LOW;
1885 else
1886 unset3 |= LSPI_OUTPUT_POLARITY_LOW;
1887 break;
1888 case TEGRA_DC_OUT_PIN_H_SYNC:
1889 if (pol == TEGRA_DC_OUT_PIN_POL_LOW)
1890 set1 |= LHS_OUTPUT_POLARITY_LOW;
1891 else
1892 unset1 |= LHS_OUTPUT_POLARITY_LOW;
1893 break;
1894 case TEGRA_DC_OUT_PIN_V_SYNC:
1895 if (pol == TEGRA_DC_OUT_PIN_POL_LOW)
1896 set1 |= LVS_OUTPUT_POLARITY_LOW;
1897 else
1898 unset1 |= LVS_OUTPUT_POLARITY_LOW;
1899 break;
1900 case TEGRA_DC_OUT_PIN_PIXEL_CLOCK:
1901 if (pol == TEGRA_DC_OUT_PIN_POL_LOW)
1902 set1 |= LSC0_OUTPUT_POLARITY_LOW;
1903 else
1904 unset1 |= LSC0_OUTPUT_POLARITY_LOW;
1905 break;
1906 default:
1907 printk("Invalid argument in function %s\n",
1908 __FUNCTION__);
1909 break;
1910 }
1911 }
1912
1913 pol1 = DC_COM_PIN_OUTPUT_POLARITY1_INIT_VAL;
1914 pol3 = DC_COM_PIN_OUTPUT_POLARITY3_INIT_VAL;
1915
1916 pol1 |= set1;
1917 pol1 &= ~unset1;
1918
1919 pol3 |= set3;
1920 pol3 &= ~unset3;
1921
1922 tegra_dc_writel(dc, pol1, DC_COM_PIN_OUTPUT_POLARITY1);
1923 tegra_dc_writel(dc, pol3, DC_COM_PIN_OUTPUT_POLARITY3);
1924}
1925
1926static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
1927{
1928 dc->out = out;
1929
1930 if (out->n_modes > 0)
1931 tegra_dc_set_mode(dc, &dc->out->modes[0]);
1932
1933 switch (out->type) {
1934 case TEGRA_DC_OUT_RGB:
1935 dc->out_ops = &tegra_dc_rgb_ops;
1936 break;
1937
1938 case TEGRA_DC_OUT_HDMI:
1939 dc->out_ops = &tegra_dc_hdmi_ops;
1940 break;
1941
1942 case TEGRA_DC_OUT_DSI:
1943 dc->out_ops = &tegra_dc_dsi_ops;
1944 break;
1945
1946 default:
1947 dc->out_ops = NULL;
1948 break;
1949 }
1950
1951 if (dc->out_ops && dc->out_ops->init)
1952 dc->out_ops->init(dc);
1953
1954}
1955
1956unsigned tegra_dc_get_out_height(const struct tegra_dc *dc)
1957{
1958 if (dc->out)
1959 return dc->out->height;
1960 else
1961 return 0;
1962}
1963EXPORT_SYMBOL(tegra_dc_get_out_height);
1964
1965unsigned tegra_dc_get_out_width(const struct tegra_dc *dc)
1966{
1967 if (dc->out)
1968 return dc->out->width;
1969 else
1970 return 0;
1971}
1972EXPORT_SYMBOL(tegra_dc_get_out_width);
1973
1974unsigned tegra_dc_get_out_max_pixclock(const struct tegra_dc *dc)
1975{
1976 if (dc->out && dc->out->max_pixclock)
1977 return dc->out->max_pixclock;
1978 else
1979 return 0;
1980}
1981EXPORT_SYMBOL(tegra_dc_get_out_max_pixclock);
1982
1983void tegra_dc_enable_crc(struct tegra_dc *dc)
1984{
1985 u32 val;
1986 tegra_dc_io_start(dc);
1987
1988 val = CRC_ALWAYS_ENABLE | CRC_INPUT_DATA_ACTIVE_DATA |
1989 CRC_ENABLE_ENABLE;
1990 tegra_dc_writel(dc, val, DC_COM_CRC_CONTROL);
1991 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
1992 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
1993}
1994
1995void tegra_dc_disable_crc(struct tegra_dc *dc)
1996{
1997 tegra_dc_writel(dc, 0x0, DC_COM_CRC_CONTROL);
1998 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
1999 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
2000
2001 tegra_dc_io_end(dc);
2002}
2003
2004u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc)
2005{
2006 int crc = 0;
2007
2008 if(!dc) {
2009 dev_err(&dc->ndev->dev, "Failed to get dc.\n");
2010 goto crc_error;
2011 }
2012
2013 /* TODO: Replace mdelay with code to sync VBlANK, since
2014 * DC_COM_CRC_CHECKSUM_LATCHED is available after VBLANK */
2015 mdelay(TEGRA_CRC_LATCHED_DELAY);
2016
2017 crc = tegra_dc_readl(dc, DC_COM_CRC_CHECKSUM_LATCHED);
2018crc_error:
2019 return crc;
2020}
2021
2022static void tegra_dc_vblank(struct work_struct *work)
2023{
2024 struct tegra_dc *dc = container_of(work, struct tegra_dc, vblank_work);
2025 bool nvsd_updated = false;
2026
2027 mutex_lock(&dc->lock);
2028
2029 /* Update the SD brightness */
2030 if (dc->enabled && dc->out->sd_settings)
2031 nvsd_updated = nvsd_update_brightness(dc);
2032
2033 mutex_unlock(&dc->lock);
2034
2035 /* Do the actual brightness update outside of the mutex */
2036 if (nvsd_updated && dc->out->sd_settings &&
2037 dc->out->sd_settings->bl_device) {
2038
2039 struct platform_device *pdev = dc->out->sd_settings->bl_device;
2040 struct backlight_device *bl = platform_get_drvdata(pdev);
2041 if (bl)
2042 backlight_update_status(bl);
2043 }
2044}
2045
2046/* Must acquire dc lock and dc one-shot lock before invoking this function.
2047 * Acquire dc one-shot lock first and then dc lock. */
2048void tegra_dc_host_trigger(struct tegra_dc *dc)
2049{
2050 /* We release the lock here to prevent deadlock between
2051 * cancel_delayed_work_sync and one-shot work. */
2052 mutex_unlock(&dc->lock);
2053
2054 cancel_delayed_work_sync(&dc->one_shot_work);
2055 mutex_lock(&dc->lock);
2056
2057 schedule_delayed_work(&dc->one_shot_work,
2058 msecs_to_jiffies(dc->one_shot_delay_ms));
2059 tegra_dc_program_bandwidth(dc);
2060 tegra_dc_writel(dc, NC_HOST_TRIG, DC_CMD_STATE_CONTROL);
2061}
2062
2063static void tegra_dc_one_shot_worker(struct work_struct *work)
2064{
2065 struct tegra_dc *dc = container_of(
2066 to_delayed_work(work), struct tegra_dc, one_shot_work);
2067 mutex_lock(&dc->lock);
2068 /* memory client has gone idle */
2069 tegra_dc_clear_bandwidth(dc);
2070 mutex_unlock(&dc->lock);
2071}
2072
2073/* return an arbitrarily large number if count overflow occurs.
2074 * make it a nice base-10 number to show up in stats output */
2075static u64 tegra_dc_underflow_count(struct tegra_dc *dc, unsigned reg)
2076{
2077 unsigned count = tegra_dc_readl(dc, reg);
2078 tegra_dc_writel(dc, 0, reg);
2079 return ((count & 0x80000000) == 0) ? count : 10000000000ll;
2080}
2081
2082static void tegra_dc_underflow_handler(struct tegra_dc *dc)
2083{
2084 u32 val;
2085 int i;
2086
2087 dc->stats.underflows++;
2088 if (dc->underflow_mask & WIN_A_UF_INT)
2089 dc->stats.underflows_a += tegra_dc_underflow_count(dc,
2090 DC_WINBUF_AD_UFLOW_STATUS);
2091 if (dc->underflow_mask & WIN_B_UF_INT)
2092 dc->stats.underflows_b += tegra_dc_underflow_count(dc,
2093 DC_WINBUF_BD_UFLOW_STATUS);
2094 if (dc->underflow_mask & WIN_C_UF_INT)
2095 dc->stats.underflows_c += tegra_dc_underflow_count(dc,
2096 DC_WINBUF_CD_UFLOW_STATUS);
2097
2098 /* Check for any underflow reset conditions */
2099 for (i = 0; i < DC_N_WINDOWS; i++) {
2100 if (dc->underflow_mask & (WIN_A_UF_INT << i)) {
2101 dc->windows[i].underflows++;
2102
2103#ifdef CONFIG_ARCH_TEGRA_2x_SOC
2104 if (dc->windows[i].underflows > 4)
2105 schedule_work(&dc->reset_work);
2106#endif
2107 } else {
2108 dc->windows[i].underflows = 0;
2109 }
2110 }
2111
2112 /* Clear the underflow mask now that we've checked it. */
2113 tegra_dc_writel(dc, dc->underflow_mask, DC_CMD_INT_STATUS);
2114 dc->underflow_mask = 0;
2115 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
2116 tegra_dc_writel(dc, val | ALL_UF_INT, DC_CMD_INT_MASK);
2117}
2118
2119#ifndef CONFIG_TEGRA_FPGA_PLATFORM
2120static bool tegra_dc_windows_are_dirty(struct tegra_dc *dc)
2121{
2122#ifndef CONFIG_TEGRA_SIMULATION_PLATFORM
2123 u32 val;
2124
2125 val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
2126 if (val & (WIN_A_UPDATE | WIN_B_UPDATE | WIN_C_UPDATE))
2127 return true;
2128#endif
2129 return false;
2130}
2131
2132static void tegra_dc_trigger_windows(struct tegra_dc *dc)
2133{
2134 u32 val, i;
2135 u32 completed = 0;
2136 u32 dirty = 0;
2137
2138 val = tegra_dc_readl(dc, DC_CMD_STATE_CONTROL);
2139 for (i = 0; i < DC_N_WINDOWS; i++) {
2140#ifdef CONFIG_TEGRA_SIMULATION_PLATFORM
2141 /* FIXME: this is not needed when the simulator
2142 clears WIN_x_UPDATE bits as in HW */
2143 dc->windows[i].dirty = 0;
2144 completed = 1;
2145#else
2146 if (!(val & (WIN_A_UPDATE << i))) {
2147 dc->windows[i].dirty = 0;
2148 completed = 1;
2149 } else {
2150 dirty = 1;
2151 }
2152#endif
2153 }
2154
2155 if (!dirty) {
2156 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
2157 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
2158 val &= ~V_BLANK_INT;
2159 else
2160 val &= ~FRAME_END_INT;
2161 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
2162 }
2163
2164 if (completed) {
2165 if (!dirty) {
2166 /* With the last completed window, go ahead
2167 and enable the vblank interrupt for nvsd. */
2168 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
2169 val |= V_BLANK_INT;
2170 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
2171 }
2172
2173 wake_up(&dc->wq);
2174 }
2175}
2176
2177static void tegra_dc_one_shot_irq(struct tegra_dc *dc, unsigned long status)
2178{
2179 if (status & V_BLANK_INT) {
2180 /* Sync up windows. */
2181 tegra_dc_trigger_windows(dc);
2182
2183 /* Schedule any additional bottom-half vblank actvities. */
2184 schedule_work(&dc->vblank_work);
2185 }
2186
2187 if (status & FRAME_END_INT) {
2188 /* Mark the frame_end as complete. */
2189 if (!completion_done(&dc->frame_end_complete))
2190 complete(&dc->frame_end_complete);
2191 }
2192}
2193
2194static void tegra_dc_continuous_irq(struct tegra_dc *dc, unsigned long status)
2195{
2196 if (status & V_BLANK_INT) {
2197 /* Schedule any additional bottom-half vblank actvities. */
2198 schedule_work(&dc->vblank_work);
2199
2200 /* All windows updated. Mask subsequent V_BLANK interrupts */
2201 if (!tegra_dc_windows_are_dirty(dc)) {
2202 u32 val;
2203
2204 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
2205 val &= ~V_BLANK_INT;
2206 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
2207 }
2208 }
2209
2210 if (status & FRAME_END_INT) {
2211 /* Mark the frame_end as complete. */
2212 if (!completion_done(&dc->frame_end_complete))
2213 complete(&dc->frame_end_complete);
2214
2215 tegra_dc_trigger_windows(dc);
2216 }
2217}
2218#endif
2219
2220static irqreturn_t tegra_dc_irq(int irq, void *ptr)
2221{
2222#ifndef CONFIG_TEGRA_FPGA_PLATFORM
2223 struct tegra_dc *dc = ptr;
2224 unsigned long status;
2225 unsigned long underflow_mask;
2226 u32 val;
2227
2228 if (!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev)) {
2229 WARN(1, "IRQ when DC not powered!\n");
2230 tegra_dc_io_start(dc);
2231 status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
2232 tegra_dc_writel(dc, status, DC_CMD_INT_STATUS);
2233 tegra_dc_io_end(dc);
2234 return IRQ_HANDLED;
2235 }
2236
2237 /* clear all status flags except underflow, save those for the worker */
2238 status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
2239 tegra_dc_writel(dc, status & ~ALL_UF_INT, DC_CMD_INT_STATUS);
2240 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
2241 tegra_dc_writel(dc, val & ~ALL_UF_INT, DC_CMD_INT_MASK);
2242
2243 /*
2244 * Overlays can get thier internal state corrupted during and underflow
2245 * condition. The only way to fix this state is to reset the DC.
2246 * if we get 4 consecutive frames with underflows, assume we're
2247 * hosed and reset.
2248 */
2249 underflow_mask = status & ALL_UF_INT;
2250
2251 /* Check underflow */
2252 if (underflow_mask) {
2253 dc->underflow_mask |= underflow_mask;
2254 schedule_delayed_work(&dc->underflow_work,
2255 msecs_to_jiffies(1));
2256 }
2257
2258 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
2259 tegra_dc_one_shot_irq(dc, status);
2260 else
2261 tegra_dc_continuous_irq(dc, status);
2262
2263 return IRQ_HANDLED;
2264#else /* CONFIG_TEGRA_FPGA_PLATFORM */
2265 return IRQ_NONE;
2266#endif /* !CONFIG_TEGRA_FPGA_PLATFORM */
2267}
2268
2269static void tegra_dc_set_color_control(struct tegra_dc *dc)
2270{
2271 u32 color_control;
2272
2273 switch (dc->out->depth) {
2274 case 3:
2275 color_control = BASE_COLOR_SIZE111;
2276 break;
2277
2278 case 6:
2279 color_control = BASE_COLOR_SIZE222;
2280 break;
2281
2282 case 8:
2283 color_control = BASE_COLOR_SIZE332;
2284 break;
2285
2286 case 9:
2287 color_control = BASE_COLOR_SIZE333;
2288 break;
2289
2290 case 12:
2291 color_control = BASE_COLOR_SIZE444;
2292 break;
2293
2294 case 15:
2295 color_control = BASE_COLOR_SIZE555;
2296 break;
2297
2298 case 16:
2299 color_control = BASE_COLOR_SIZE565;
2300 break;
2301
2302 case 18:
2303 color_control = BASE_COLOR_SIZE666;
2304 break;
2305
2306 default:
2307 color_control = BASE_COLOR_SIZE888;
2308 break;
2309 }
2310
2311 switch (dc->out->dither) {
2312 case TEGRA_DC_DISABLE_DITHER:
2313 color_control |= DITHER_CONTROL_DISABLE;
2314 break;
2315 case TEGRA_DC_ORDERED_DITHER:
2316 color_control |= DITHER_CONTROL_ORDERED;
2317 break;
2318 case TEGRA_DC_ERRDIFF_DITHER:
2319 /* The line buffer for error-diffusion dither is limited
2320 * to 1280 pixels per line. This limits the maximum
2321 * horizontal active area size to 1280 pixels when error
2322 * diffusion is enabled.
2323 */
2324 BUG_ON(dc->mode.h_active > 1280);
2325 color_control |= DITHER_CONTROL_ERRDIFF;
2326 break;
2327 }
2328
2329 tegra_dc_writel(dc, color_control, DC_DISP_DISP_COLOR_CONTROL);
2330}
2331
2332static u32 get_syncpt(struct tegra_dc *dc, int idx)
2333{
2334 u32 syncpt_id;
2335
2336 switch (dc->ndev->id) {
2337 case 0:
2338 switch (idx) {
2339 case 0:
2340 syncpt_id = NVSYNCPT_DISP0_A;
2341 break;
2342 case 1:
2343 syncpt_id = NVSYNCPT_DISP0_B;
2344 break;
2345 case 2:
2346 syncpt_id = NVSYNCPT_DISP0_C;
2347 break;
2348 default:
2349 BUG();
2350 break;
2351 }
2352 break;
2353 case 1:
2354 switch (idx) {
2355 case 0:
2356 syncpt_id = NVSYNCPT_DISP1_A;
2357 break;
2358 case 1:
2359 syncpt_id = NVSYNCPT_DISP1_B;
2360 break;
2361 case 2:
2362 syncpt_id = NVSYNCPT_DISP1_C;
2363 break;
2364 default:
2365 BUG();
2366 break;
2367 }
2368 break;
2369 default:
2370 BUG();
2371 break;
2372 }
2373
2374 return syncpt_id;
2375}
2376
2377static int tegra_dc_init(struct tegra_dc *dc)
2378{
2379 int i;
2380
2381 tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
2382 if (dc->ndev->id == 0) {
2383 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0A,
2384 TEGRA_MC_PRIO_MED);
2385 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0B,
2386 TEGRA_MC_PRIO_MED);
2387 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0C,
2388 TEGRA_MC_PRIO_MED);
2389 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY1B,
2390 TEGRA_MC_PRIO_MED);
2391 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAYHC,
2392 TEGRA_MC_PRIO_HIGH);
2393 } else if (dc->ndev->id == 1) {
2394 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0AB,
2395 TEGRA_MC_PRIO_MED);
2396 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0BB,
2397 TEGRA_MC_PRIO_MED);
2398 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY0CB,
2399 TEGRA_MC_PRIO_MED);
2400 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAY1BB,
2401 TEGRA_MC_PRIO_MED);
2402 tegra_mc_set_priority(TEGRA_MC_CLIENT_DISPLAYHCB,
2403 TEGRA_MC_PRIO_HIGH);
2404 }
2405 tegra_dc_writel(dc, 0x00000100 | dc->vblank_syncpt,
2406 DC_CMD_CONT_SYNCPT_VSYNC);
2407 tegra_dc_writel(dc, 0x00004700, DC_CMD_INT_TYPE);
2408 tegra_dc_writel(dc, 0x0001c700, DC_CMD_INT_POLARITY);
2409 tegra_dc_writel(dc, 0x00202020, DC_DISP_MEM_HIGH_PRIORITY);
2410 tegra_dc_writel(dc, 0x00010101, DC_DISP_MEM_HIGH_PRIORITY_TIMER);
2411
2412 /* enable interrupts for vblank, frame_end and underflows */
2413 tegra_dc_writel(dc, (FRAME_END_INT | V_BLANK_INT | ALL_UF_INT),
2414 DC_CMD_INT_ENABLE);
2415 tegra_dc_writel(dc, ALL_UF_INT, DC_CMD_INT_MASK);
2416
2417 tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
2418
2419 tegra_dc_set_color_control(dc);
2420 for (i = 0; i < DC_N_WINDOWS; i++) {
2421 struct tegra_dc_win *win = &dc->windows[i];
2422 tegra_dc_writel(dc, WINDOW_A_SELECT << i,
2423 DC_CMD_DISPLAY_WINDOW_HEADER);
2424 tegra_dc_set_csc(dc, &win->csc);
2425 tegra_dc_set_lut(dc, win);
2426 tegra_dc_set_scaling_filter(dc);
2427 }
2428
2429
2430 for (i = 0; i < dc->n_windows; i++) {
2431 u32 syncpt = get_syncpt(dc, i);
2432
2433 dc->syncpt[i].id = syncpt;
2434
2435 dc->syncpt[i].min = dc->syncpt[i].max =
2436 nvhost_syncpt_read(&nvhost_get_host(dc->ndev)->syncpt,
2437 syncpt);
2438 }
2439
2440 print_mode(dc, &dc->mode, __func__);
2441
2442 if (dc->mode.pclk)
2443 if (tegra_dc_program_mode(dc, &dc->mode))
2444 return -EINVAL;
2445
2446 /* Initialize SD AFTER the modeset.
2447 nvsd_init handles the sd_settings = NULL case. */
2448 nvsd_init(dc, dc->out->sd_settings);
2449
2450 return 0;
2451}
2452
2453static bool _tegra_dc_controller_enable(struct tegra_dc *dc)
2454{
2455 int failed_init = 0;
2456
2457 if (dc->out->enable)
2458 dc->out->enable();
2459
2460 tegra_dc_setup_clk(dc, dc->clk);
2461 clk_enable(dc->clk);
2462
2463 /* do not accept interrupts during initialization */
2464 tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE);
2465 tegra_dc_writel(dc, 0, DC_CMD_INT_MASK);
2466
2467 enable_dc_irq(dc->irq);
2468
2469 failed_init = tegra_dc_init(dc);
2470 if (failed_init) {
2471 _tegra_dc_controller_disable(dc);
2472 return false;
2473 }
2474
2475 if (dc->out_ops && dc->out_ops->enable)
2476 dc->out_ops->enable(dc);
2477
2478 if (dc->out->postpoweron)
2479 dc->out->postpoweron();
2480
2481 /* force a full blending update */
2482 dc->blend.z[0] = -1;
2483
2484 tegra_dc_ext_enable(dc->ext);
2485
2486 return true;
2487}
2488
2489#ifdef CONFIG_ARCH_TEGRA_2x_SOC
2490static bool _tegra_dc_controller_reset_enable(struct tegra_dc *dc)
2491{
2492 bool ret = true;
2493
2494 if (dc->out->enable)
2495 dc->out->enable();
2496
2497 tegra_dc_setup_clk(dc, dc->clk);
2498 clk_enable(dc->clk);
2499
2500 if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) {
2501 mutex_lock(&tegra_dcs[1]->lock);
2502 disable_irq(tegra_dcs[1]->irq);
2503 } else if (dc->ndev->id == 1 && tegra_dcs[0] != NULL) {
2504 mutex_lock(&tegra_dcs[0]->lock);
2505 disable_irq(tegra_dcs[0]->irq);
2506 }
2507
2508 msleep(5);
2509 tegra_periph_reset_assert(dc->clk);
2510 msleep(2);
2511#ifdef CONFIG_TEGRA_SILICON_PLATFORM
2512 tegra_periph_reset_deassert(dc->clk);
2513 msleep(1);
2514#endif
2515
2516 if (dc->ndev->id == 0 && tegra_dcs[1] != NULL) {
2517 enable_dc_irq(tegra_dcs[1]->irq);
2518 mutex_unlock(&tegra_dcs[1]->lock);
2519 } else if (dc->ndev->id == 1 && tegra_dcs[0] != NULL) {
2520 enable_dc_irq(tegra_dcs[0]->irq);
2521 mutex_unlock(&tegra_dcs[0]->lock);
2522 }
2523
2524 enable_dc_irq(dc->irq);
2525
2526 if (tegra_dc_init(dc)) {
2527 dev_err(&dc->ndev->dev, "cannot initialize\n");
2528 ret = false;
2529 }
2530
2531 if (dc->out_ops && dc->out_ops->enable)
2532 dc->out_ops->enable(dc);
2533
2534 if (dc->out->postpoweron)
2535 dc->out->postpoweron();
2536
2537 /* force a full blending update */
2538 dc->blend.z[0] = -1;
2539
2540 tegra_dc_ext_enable(dc->ext);
2541
2542 if (!ret) {
2543 dev_err(&dc->ndev->dev, "initialization failed,disabling");
2544 _tegra_dc_controller_disable(dc);
2545 }
2546
2547 return ret;
2548}
2549#endif
2550
2551static bool _tegra_dc_enable(struct tegra_dc *dc)
2552{
2553 if (dc->mode.pclk == 0)
2554 return false;
2555
2556 if (!dc->out)
2557 return false;
2558
2559 tegra_dc_io_start(dc);
2560
2561 return _tegra_dc_controller_enable(dc);
2562}
2563
2564void tegra_dc_enable(struct tegra_dc *dc)
2565{
2566 mutex_lock(&dc->lock);
2567
2568 if (!dc->enabled)
2569 dc->enabled = _tegra_dc_enable(dc);
2570
2571 mutex_unlock(&dc->lock);
2572}
2573
2574static void _tegra_dc_controller_disable(struct tegra_dc *dc)
2575{
2576 unsigned i;
2577
2578 if (dc->out_ops && dc->out_ops->disable)
2579 dc->out_ops->disable(dc);
2580
2581 tegra_dc_writel(dc, 0, DC_CMD_INT_MASK);
2582 tegra_dc_writel(dc, 0, DC_CMD_INT_ENABLE);
2583 disable_irq(dc->irq);
2584
2585 tegra_dc_clear_bandwidth(dc);
2586 clk_disable(dc->clk);
2587 tegra_dvfs_set_rate(dc->clk, 0);
2588
2589 if (dc->out && dc->out->disable)
2590 dc->out->disable();
2591
2592 for (i = 0; i < dc->n_windows; i++) {
2593 struct tegra_dc_win *w = &dc->windows[i];
2594
2595 /* reset window bandwidth */
2596 w->bandwidth = 0;
2597 w->new_bandwidth = 0;
2598
2599 /* disable windows */
2600 w->flags &= ~TEGRA_WIN_FLAG_ENABLED;
2601
2602 /* flush any pending syncpt waits */
2603 while (dc->syncpt[i].min < dc->syncpt[i].max) {
2604 dc->syncpt[i].min++;
2605 nvhost_syncpt_cpu_incr(
2606 &nvhost_get_host(dc->ndev)->syncpt,
2607 dc->syncpt[i].id);
2608 }
2609 }
2610}
2611
2612void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable)
2613{
2614#if 0 /* underflow interrupt is already enabled by dc reset worker */
2615 u32 val;
2616 if (dc->enabled) {
2617 val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
2618 if (enable)
2619 val |= (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
2620 else
2621 val &= ~(WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
2622 tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
2623 }
2624#endif
2625}
2626
2627bool tegra_dc_stats_get(struct tegra_dc *dc)
2628{
2629#if 0 /* right now it is always enabled */
2630 u32 val;
2631 bool res;
2632
2633 if (dc->enabled) {
2634 val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
2635 res = !!(val & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT));
2636 } else {
2637 res = false;
2638 }
2639
2640 return res;
2641#endif
2642 return true;
2643}
2644
2645/* make the screen blank by disabling all windows */
2646void tegra_dc_blank(struct tegra_dc *dc)
2647{
2648 struct tegra_dc_win *dcwins[DC_N_WINDOWS];
2649 unsigned i;
2650
2651 for (i = 0; i < DC_N_WINDOWS; i++) {
2652 dcwins[i] = tegra_dc_get_window(dc, i);
2653 dcwins[i]->flags &= ~TEGRA_WIN_FLAG_ENABLED;
2654 }
2655
2656 tegra_dc_update_windows(dcwins, DC_N_WINDOWS);
2657 tegra_dc_sync_windows(dcwins, DC_N_WINDOWS);
2658}
2659
2660static void _tegra_dc_disable(struct tegra_dc *dc)
2661{
2662 _tegra_dc_controller_disable(dc);
2663 tegra_dc_io_end(dc);
2664}
2665
2666void tegra_dc_disable(struct tegra_dc *dc)
2667{
2668 tegra_dc_ext_disable(dc->ext);
2669
2670 /* it's important that new underflow work isn't scheduled before the
2671 * lock is acquired. */
2672 cancel_delayed_work_sync(&dc->underflow_work);
2673 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
2674 mutex_lock(&dc->one_shot_lock);
2675 cancel_delayed_work_sync(&dc->one_shot_work);
2676 }
2677
2678 mutex_lock(&dc->lock);
2679
2680 if (dc->enabled) {
2681 dc->enabled = false;
2682
2683 if (!dc->suspended)
2684 _tegra_dc_disable(dc);
2685 }
2686
2687#ifdef CONFIG_SWITCH
2688 switch_set_state(&dc->modeset_switch, 0);
2689#endif
2690
2691 mutex_unlock(&dc->lock);
2692 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
2693 mutex_unlock(&dc->one_shot_lock);
2694}
2695
2696#ifdef CONFIG_ARCH_TEGRA_2x_SOC
2697static void tegra_dc_reset_worker(struct work_struct *work)
2698{
2699 struct tegra_dc *dc =
2700 container_of(work, struct tegra_dc, reset_work);
2701
2702 unsigned long val = 0;
2703
2704 mutex_lock(&shared_lock);
2705
2706 dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
2707
2708 tegra_dc_ext_disable(dc->ext);
2709
2710 mutex_lock(&dc->lock);
2711
2712 if (dc->enabled == false)
2713 goto unlock;
2714
2715 dc->enabled = false;
2716
2717 /*
2718 * off host read bus
2719 */
2720 val = tegra_dc_readl(dc, DC_CMD_CONT_SYNCPT_VSYNC);
2721 val &= ~(0x00000100);
2722 tegra_dc_writel(dc, val, DC_CMD_CONT_SYNCPT_VSYNC);
2723
2724 /*
2725 * set DC to STOP mode
2726 */
2727 tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND);
2728
2729 msleep(10);
2730
2731 _tegra_dc_controller_disable(dc);
2732
2733 /* _tegra_dc_controller_reset_enable deasserts reset */
2734 _tegra_dc_controller_reset_enable(dc);
2735
2736 dc->enabled = true;
2737unlock:
2738 mutex_unlock(&dc->lock);
2739 mutex_unlock(&shared_lock);
2740}
2741#endif
2742
2743static void tegra_dc_underflow_worker(struct work_struct *work)
2744{
2745 struct tegra_dc *dc = container_of(
2746 to_delayed_work(work), struct tegra_dc, underflow_work);
2747
2748 mutex_lock(&dc->lock);
2749 if (dc->enabled) {
2750 tegra_dc_underflow_handler(dc);
2751 }
2752 mutex_unlock(&dc->lock);
2753}
2754
2755#ifdef CONFIG_SWITCH
2756static ssize_t switch_modeset_print_mode(struct switch_dev *sdev, char *buf)
2757{
2758 struct tegra_dc *dc =
2759 container_of(sdev, struct tegra_dc, modeset_switch);
2760
2761 if (!sdev->state)
2762 return sprintf(buf, "offline\n");
2763
2764 return sprintf(buf, "%dx%d\n", dc->mode.h_active, dc->mode.v_active);
2765}
2766#endif
2767
2768static int tegra_dc_probe(struct nvhost_device *ndev)
2769{
2770 struct tegra_dc *dc;
2771 struct clk *clk;
2772 struct clk *emc_clk;
2773 struct resource *res;
2774 struct resource *base_res;
2775 struct resource *fb_mem = NULL;
2776 int ret = 0;
2777 void __iomem *base;
2778 int irq;
2779 int i;
2780
2781 if (!ndev->dev.platform_data) {
2782 dev_err(&ndev->dev, "no platform data\n");
2783 return -ENOENT;
2784 }
2785
2786 dc = kzalloc(sizeof(struct tegra_dc), GFP_KERNEL);
2787 if (!dc) {
2788 dev_err(&ndev->dev, "can't allocate memory for tegra_dc\n");
2789 return -ENOMEM;
2790 }
2791
2792 irq = nvhost_get_irq_byname(ndev, "irq");
2793 if (irq <= 0) {
2794 dev_err(&ndev->dev, "no irq\n");
2795 ret = -ENOENT;
2796 goto err_free;
2797 }
2798
2799 res = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "regs");
2800 if (!res) {
2801 dev_err(&ndev->dev, "no mem resource\n");
2802 ret = -ENOENT;
2803 goto err_free;
2804 }
2805
2806 base_res = request_mem_region(res->start, resource_size(res), ndev->name);
2807 if (!base_res) {
2808 dev_err(&ndev->dev, "request_mem_region failed\n");
2809 ret = -EBUSY;
2810 goto err_free;
2811 }
2812
2813 base = ioremap(res->start, resource_size(res));
2814 if (!base) {
2815 dev_err(&ndev->dev, "registers can't be mapped\n");
2816 ret = -EBUSY;
2817 goto err_release_resource_reg;
2818 }
2819
2820 fb_mem = nvhost_get_resource_byname(ndev, IORESOURCE_MEM, "fbmem");
2821
2822 clk = clk_get(&ndev->dev, NULL);
2823 if (IS_ERR_OR_NULL(clk)) {
2824 dev_err(&ndev->dev, "can't get clock\n");
2825 ret = -ENOENT;
2826 goto err_iounmap_reg;
2827 }
2828
2829 emc_clk = clk_get(&ndev->dev, "emc");
2830 if (IS_ERR_OR_NULL(emc_clk)) {
2831 dev_err(&ndev->dev, "can't get emc clock\n");
2832 ret = -ENOENT;
2833 goto err_put_clk;
2834 }
2835
2836 dc->clk = clk;
2837 dc->emc_clk = emc_clk;
2838 dc->shift_clk_div = 1;
2839 /* Initialize one shot work delay, it will be assigned by dsi
2840 * according to refresh rate later. */
2841 dc->one_shot_delay_ms = 40;
2842
2843 dc->base_res = base_res;
2844 dc->base = base;
2845 dc->irq = irq;
2846 dc->ndev = ndev;
2847 dc->pdata = ndev->dev.platform_data;
2848
2849 /*
2850 * The emc is a shared clock, it will be set based on
2851 * the requirements for each user on the bus.
2852 */
2853 dc->emc_clk_rate = 0;
2854
2855 if (dc->pdata->flags & TEGRA_DC_FLAG_ENABLED)
2856 dc->enabled = true;
2857
2858 mutex_init(&dc->lock);
2859 mutex_init(&dc->one_shot_lock);
2860 init_completion(&dc->frame_end_complete);
2861 init_waitqueue_head(&dc->wq);
2862#ifdef CONFIG_ARCH_TEGRA_2x_SOC
2863 INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
2864#endif
2865 INIT_WORK(&dc->vblank_work, tegra_dc_vblank);
2866 INIT_DELAYED_WORK(&dc->underflow_work, tegra_dc_underflow_worker);
2867 INIT_DELAYED_WORK(&dc->one_shot_work, tegra_dc_one_shot_worker);
2868
2869 tegra_dc_init_lut_defaults(&dc->fb_lut);
2870
2871 dc->n_windows = DC_N_WINDOWS;
2872 for (i = 0; i < dc->n_windows; i++) {
2873 struct tegra_dc_win *win = &dc->windows[i];
2874 win->idx = i;
2875 win->dc = dc;
2876 tegra_dc_init_csc_defaults(&win->csc);
2877 tegra_dc_init_lut_defaults(&win->lut);
2878 }
2879
2880 ret = tegra_dc_set(dc, ndev->id);
2881 if (ret < 0) {
2882 dev_err(&ndev->dev, "can't add dc\n");
2883 goto err_free_irq;
2884 }
2885
2886 nvhost_set_drvdata(ndev, dc);
2887
2888#ifdef CONFIG_SWITCH
2889 dc->modeset_switch.name = dev_name(&ndev->dev);
2890 dc->modeset_switch.state = 0;
2891 dc->modeset_switch.print_state = switch_modeset_print_mode;
2892 switch_dev_register(&dc->modeset_switch);
2893#endif
2894
2895 if (dc->pdata->default_out)
2896 tegra_dc_set_out(dc, dc->pdata->default_out);
2897 else
2898 dev_err(&ndev->dev, "No default output specified. Leaving output disabled.\n");
2899
2900 dc->vblank_syncpt = (dc->ndev->id == 0) ?
2901 NVSYNCPT_VBLANK0 : NVSYNCPT_VBLANK1;
2902
2903 dc->ext = tegra_dc_ext_register(ndev, dc);
2904 if (IS_ERR_OR_NULL(dc->ext)) {
2905 dev_warn(&ndev->dev, "Failed to enable Tegra DC extensions.\n");
2906 dc->ext = NULL;
2907 }
2908
2909 /* interrupt handler must be registered before tegra_fb_register() */
2910 if (request_irq(irq, tegra_dc_irq, IRQF_DISABLED,
2911 dev_name(&ndev->dev), dc)) {
2912 dev_err(&ndev->dev, "request_irq %d failed\n", irq);
2913 ret = -EBUSY;
2914 goto err_put_emc_clk;
2915 }
2916
2917 /* hack to balance enable_irq calls in _tegra_dc_enable() */
2918 disable_dc_irq(dc->irq);
2919
2920 mutex_lock(&dc->lock);
2921 if (dc->enabled)
2922 _tegra_dc_enable(dc);
2923 mutex_unlock(&dc->lock);
2924
2925 tegra_dc_create_debugfs(dc);
2926
2927 dev_info(&ndev->dev, "probed\n");
2928
2929 if (dc->pdata->fb) {
2930 if (dc->pdata->fb->bits_per_pixel == -1) {
2931 unsigned long fmt;
2932 tegra_dc_writel(dc,
2933 WINDOW_A_SELECT << dc->pdata->fb->win,
2934 DC_CMD_DISPLAY_WINDOW_HEADER);
2935
2936 fmt = tegra_dc_readl(dc, DC_WIN_COLOR_DEPTH);
2937 dc->pdata->fb->bits_per_pixel =
2938 tegra_dc_fmt_bpp(fmt);
2939 }
2940
2941 dc->fb = tegra_fb_register(ndev, dc, dc->pdata->fb, fb_mem);
2942 if (IS_ERR_OR_NULL(dc->fb))
2943 dc->fb = NULL;
2944 }
2945
2946 if (dc->out && dc->out->hotplug_init)
2947 dc->out->hotplug_init();
2948
2949 if (dc->out_ops && dc->out_ops->detect)
2950 dc->out_ops->detect(dc);
2951 else
2952 dc->connected = true;
2953
2954 tegra_dc_create_sysfs(&dc->ndev->dev);
2955
2956 return 0;
2957
2958err_free_irq:
2959 free_irq(irq, dc);
2960err_put_emc_clk:
2961 clk_put(emc_clk);
2962err_put_clk:
2963 clk_put(clk);
2964err_iounmap_reg:
2965 iounmap(base);
2966 if (fb_mem)
2967 release_resource(fb_mem);
2968err_release_resource_reg:
2969 release_resource(base_res);
2970err_free:
2971 kfree(dc);
2972
2973 return ret;
2974}
2975
2976static int tegra_dc_remove(struct nvhost_device *ndev)
2977{
2978 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
2979
2980 tegra_dc_remove_sysfs(&dc->ndev->dev);
2981 tegra_dc_remove_debugfs(dc);
2982
2983 if (dc->fb) {
2984 tegra_fb_unregister(dc->fb);
2985 if (dc->fb_mem)
2986 release_resource(dc->fb_mem);
2987 }
2988
2989 tegra_dc_ext_disable(dc->ext);
2990
2991 if (dc->ext)
2992 tegra_dc_ext_unregister(dc->ext);
2993
2994 if (dc->enabled)
2995 _tegra_dc_disable(dc);
2996
2997#ifdef CONFIG_SWITCH
2998 switch_dev_unregister(&dc->modeset_switch);
2999#endif
3000 free_irq(dc->irq, dc);
3001 clk_put(dc->emc_clk);
3002 clk_put(dc->clk);
3003 iounmap(dc->base);
3004 if (dc->fb_mem)
3005 release_resource(dc->base_res);
3006 kfree(dc);
3007 tegra_dc_set(NULL, ndev->id);
3008 return 0;
3009}
3010
3011#ifdef CONFIG_PM
3012static int tegra_dc_suspend(struct nvhost_device *ndev, pm_message_t state)
3013{
3014 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
3015
3016 dev_info(&ndev->dev, "suspend\n");
3017
3018 tegra_dc_ext_disable(dc->ext);
3019
3020 mutex_lock(&dc->lock);
3021
3022 if (dc->out_ops && dc->out_ops->suspend)
3023 dc->out_ops->suspend(dc);
3024
3025 if (dc->enabled) {
3026 _tegra_dc_disable(dc);
3027
3028 dc->suspended = true;
3029 }
3030
3031 if (dc->out && dc->out->postsuspend) {
3032 dc->out->postsuspend();
3033 if (dc->out->type && dc->out->type == TEGRA_DC_OUT_HDMI)
3034 /*
3035 * avoid resume event due to voltage falling
3036 */
3037 msleep(100);
3038 }
3039
3040 mutex_unlock(&dc->lock);
3041
3042 return 0;
3043}
3044
3045static int tegra_dc_resume(struct nvhost_device *ndev)
3046{
3047 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
3048
3049 dev_info(&ndev->dev, "resume\n");
3050
3051 mutex_lock(&dc->lock);
3052 dc->suspended = false;
3053
3054 if (dc->enabled)
3055 _tegra_dc_enable(dc);
3056
3057 if (dc->out && dc->out->hotplug_init)
3058 dc->out->hotplug_init();
3059
3060 if (dc->out_ops && dc->out_ops->resume)
3061 dc->out_ops->resume(dc);
3062 mutex_unlock(&dc->lock);
3063
3064 return 0;
3065}
3066
3067#endif /* CONFIG_PM */
3068
3069extern int suspend_set(const char *val, struct kernel_param *kp)
3070{
3071 if (!strcmp(val, "dump"))
3072 dump_regs(tegra_dcs[0]);
3073#ifdef CONFIG_PM
3074 else if (!strcmp(val, "suspend"))
3075 tegra_dc_suspend(tegra_dcs[0]->ndev, PMSG_SUSPEND);
3076 else if (!strcmp(val, "resume"))
3077 tegra_dc_resume(tegra_dcs[0]->ndev);
3078#endif
3079
3080 return 0;
3081}
3082
3083extern int suspend_get(char *buffer, struct kernel_param *kp)
3084{
3085 return 0;
3086}
3087
3088int suspend;
3089
3090module_param_call(suspend, suspend_set, suspend_get, &suspend, 0644);
3091
3092struct nvhost_driver tegra_dc_driver = {
3093 .driver = {
3094 .name = "tegradc",
3095 .owner = THIS_MODULE,
3096 },
3097 .probe = tegra_dc_probe,
3098 .remove = tegra_dc_remove,
3099#ifdef CONFIG_PM
3100 .suspend = tegra_dc_suspend,
3101 .resume = tegra_dc_resume,
3102#endif
3103};
3104
3105static int __init tegra_dc_module_init(void)
3106{
3107 int ret = tegra_dc_ext_module_init();
3108 if (ret)
3109 return ret;
3110 return nvhost_driver_register(&tegra_dc_driver);
3111}
3112
3113static void __exit tegra_dc_module_exit(void)
3114{
3115 nvhost_driver_unregister(&tegra_dc_driver);
3116 tegra_dc_ext_module_exit();
3117}
3118
3119module_exit(tegra_dc_module_exit);
3120module_init(tegra_dc_module_init);
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
new file mode 100644
index 00000000000..a10e648debc
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -0,0 +1,220 @@
1/*
2 * drivers/video/tegra/dc/dc_priv.h
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H
19#define __DRIVERS_VIDEO_TEGRA_DC_DC_PRIV_H
20
21#include <linux/io.h>
22#include <linux/mutex.h>
23#include <linux/wait.h>
24#include <linux/completion.h>
25#include <linux/switch.h>
26
27#include <mach/dc.h>
28
29#include "../host/dev.h"
30#include "../host/host1x/host1x_syncpt.h"
31
32#include <mach/tegra_dc_ext.h>
33
34#define WIN_IS_TILED(win) ((win)->flags & TEGRA_WIN_FLAG_TILED)
35#define WIN_IS_ENABLED(win) ((win)->flags & TEGRA_WIN_FLAG_ENABLED)
36
37#define NEED_UPDATE_EMC_ON_EVERY_FRAME (windows_idle_detection_time == 0)
38
39/* DDR: 8 bytes transfer per clock */
40#define DDR_BW_TO_FREQ(bw) ((bw) / 8)
41
42#if defined(CONFIG_TEGRA_EMC_TO_DDR_CLOCK)
43#define EMC_BW_TO_FREQ(bw) (DDR_BW_TO_FREQ(bw) * CONFIG_TEGRA_EMC_TO_DDR_CLOCK)
44#else
45#define EMC_BW_TO_FREQ(bw) (DDR_BW_TO_FREQ(bw) * 2)
46#endif
47
48struct tegra_dc;
49
50struct tegra_dc_blend {
51 unsigned z[DC_N_WINDOWS];
52 unsigned flags[DC_N_WINDOWS];
53};
54
55struct tegra_dc_out_ops {
56 /* initialize output. dc clocks are not on at this point */
57 int (*init)(struct tegra_dc *dc);
58 /* destroy output. dc clocks are not on at this point */
59 void (*destroy)(struct tegra_dc *dc);
60 /* detect connected display. can sleep.*/
61 bool (*detect)(struct tegra_dc *dc);
62 /* enable output. dc clocks are on at this point */
63 void (*enable)(struct tegra_dc *dc);
64 /* disable output. dc clocks are on at this point */
65 void (*disable)(struct tegra_dc *dc);
66
67 /* suspend output. dc clocks are on at this point */
68 void (*suspend)(struct tegra_dc *dc);
69 /* resume output. dc clocks are on at this point */
70 void (*resume)(struct tegra_dc *dc);
71};
72
73struct tegra_dc {
74 struct nvhost_device *ndev;
75 struct tegra_dc_platform_data *pdata;
76
77 struct resource *base_res;
78 void __iomem *base;
79 int irq;
80
81 struct clk *clk;
82 struct clk *emc_clk;
83 int emc_clk_rate;
84 int new_emc_clk_rate;
85 u32 shift_clk_div;
86
87 bool connected;
88 bool enabled;
89 bool suspended;
90
91 struct tegra_dc_out *out;
92 struct tegra_dc_out_ops *out_ops;
93 void *out_data;
94
95 struct tegra_dc_mode mode;
96
97 struct tegra_dc_win windows[DC_N_WINDOWS];
98 struct tegra_dc_blend blend;
99 int n_windows;
100
101 wait_queue_head_t wq;
102
103 struct mutex lock;
104 struct mutex one_shot_lock;
105
106 struct resource *fb_mem;
107 struct tegra_fb_info *fb;
108
109 struct {
110 u32 id;
111 u32 min;
112 u32 max;
113 } syncpt[DC_N_WINDOWS];
114 u32 vblank_syncpt;
115
116 unsigned long underflow_mask;
117 struct work_struct reset_work;
118
119#ifdef CONFIG_SWITCH
120 struct switch_dev modeset_switch;
121#endif
122
123 struct completion frame_end_complete;
124
125 struct work_struct vblank_work;
126
127 struct {
128 u64 underflows;
129 u64 underflows_a;
130 u64 underflows_b;
131 u64 underflows_c;
132 } stats;
133
134 struct tegra_dc_ext *ext;
135
136#ifdef CONFIG_DEBUG_FS
137 struct dentry *debugdir;
138#endif
139 struct tegra_dc_lut fb_lut;
140 struct delayed_work underflow_work;
141 u32 one_shot_delay_ms;
142 struct delayed_work one_shot_work;
143};
144
145static inline void tegra_dc_io_start(struct tegra_dc *dc)
146{
147 nvhost_module_busy(nvhost_get_host(dc->ndev)->dev);
148}
149
150static inline void tegra_dc_io_end(struct tegra_dc *dc)
151{
152 nvhost_module_idle(nvhost_get_host(dc->ndev)->dev);
153}
154
155static inline unsigned long tegra_dc_readl(struct tegra_dc *dc,
156 unsigned long reg)
157{
158 BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
159 return readl(dc->base + reg * 4);
160}
161
162static inline void tegra_dc_writel(struct tegra_dc *dc, unsigned long val,
163 unsigned long reg)
164{
165 BUG_ON(!nvhost_module_powered(nvhost_get_host(dc->ndev)->dev));
166 writel(val, dc->base + reg * 4);
167}
168
169static inline void _tegra_dc_write_table(struct tegra_dc *dc, const u32 *table,
170 unsigned len)
171{
172 int i;
173
174 for (i = 0; i < len; i++)
175 tegra_dc_writel(dc, table[i * 2 + 1], table[i * 2]);
176}
177
178#define tegra_dc_write_table(dc, table) \
179 _tegra_dc_write_table(dc, table, ARRAY_SIZE(table) / 2)
180
181static inline void tegra_dc_set_outdata(struct tegra_dc *dc, void *data)
182{
183 dc->out_data = data;
184}
185
186static inline void *tegra_dc_get_outdata(struct tegra_dc *dc)
187{
188 return dc->out_data;
189}
190
191static inline unsigned long tegra_dc_get_default_emc_clk_rate(
192 struct tegra_dc *dc)
193{
194 return dc->pdata->emc_clk_rate ? dc->pdata->emc_clk_rate : ULONG_MAX;
195}
196
197void tegra_dc_setup_clk(struct tegra_dc *dc, struct clk *clk);
198
199extern struct tegra_dc_out_ops tegra_dc_rgb_ops;
200extern struct tegra_dc_out_ops tegra_dc_hdmi_ops;
201extern struct tegra_dc_out_ops tegra_dc_dsi_ops;
202
203/* defined in dc_sysfs.c, used by dc.c */
204void __devexit tegra_dc_remove_sysfs(struct device *dev);
205void tegra_dc_create_sysfs(struct device *dev);
206
207/* defined in dc.c, used by dc_sysfs.c */
208void tegra_dc_stats_enable(struct tegra_dc *dc, bool enable);
209bool tegra_dc_stats_get(struct tegra_dc *dc);
210
211/* defined in dc.c, used by dc_sysfs.c */
212u32 tegra_dc_read_checksum_latched(struct tegra_dc *dc);
213void tegra_dc_enable_crc(struct tegra_dc *dc);
214void tegra_dc_disable_crc(struct tegra_dc *dc);
215
216void tegra_dc_set_out_pin_polars(struct tegra_dc *dc,
217 const struct tegra_dc_out_pin *pins,
218 const unsigned int n_pins);
219#endif
220
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
new file mode 100644
index 00000000000..22379a19408
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -0,0 +1,555 @@
1/*
2 * drivers/video/tegra/dc/dc_reg.h
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2010-2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#ifndef __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H
21#define __DRIVERS_VIDEO_TEGRA_DC_DC_REG_H
22
23#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
24#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
25#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002
26#define DC_CMD_WIN_A_INCR_SYNCPT 0x008
27#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009
28#define DC_CMD_WIN_A_INCR_SYNCPT_ERROR 0x00a
29#define DC_CMD_WIN_B_INCR_SYNCPT 0x010
30#define DC_CMD_WIN_B_INCR_SYNCPT_CNTRL 0x011
31#define DC_CMD_WIN_B_INCR_SYNCPT_ERROR 0x012
32#define DC_CMD_WIN_C_INCR_SYNCPT 0x018
33#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019
34#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a
35#define DC_CMD_CONT_SYNCPT_VSYNC 0x028
36#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
37#define MSF_POLARITY_HIGH (0 << 0)
38#define MSF_POLARITY_LOW (1 << 0)
39#define MSF_DISABLE (0 << 1)
40#define MSF_ENABLE (1 << 1)
41#define MSF_LSPI (0 << 2)
42#define MSF_LDC (1 << 2)
43#define MSF_LSDI (2 << 2)
44
45#define DC_CMD_DISPLAY_COMMAND 0x032
46#define DISP_COMMAND_RAISE (1 << 0)
47#define DISP_CTRL_MODE_STOP (0 << 5)
48#define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
49#define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
50#define DISP_COMMAND_RAISE_VECTOR(x) (((x) & 0x1f) << 22)
51#define DISP_COMMAND_RAISE_CHANNEL_ID(x) (((x) & 0xf) << 27)
52
53#define DC_CMD_SIGNAL_RAISE 0x033
54#define DC_CMD_DISPLAY_POWER_CONTROL 0x036
55#define PW0_ENABLE (1 << 0)
56#define PW1_ENABLE (1 << 2)
57#define PW2_ENABLE (1 << 4)
58#define PW3_ENABLE (1 << 6)
59#define PW4_ENABLE (1 << 8)
60#define PM0_ENABLE (1 << 16)
61#define PM1_ENABLE (1 << 18)
62#define SPI_ENABLE (1 << 24)
63#define HSPI_ENABLE (1 << 25)
64
65#define DC_CMD_INT_STATUS 0x037
66#define DC_CMD_INT_MASK 0x038
67#define DC_CMD_INT_ENABLE 0x039
68#define DC_CMD_INT_TYPE 0x03a
69#define DC_CMD_INT_POLARITY 0x03b
70#define CTXSW_INT (1 << 0)
71#define FRAME_END_INT (1 << 1)
72#define V_BLANK_INT (1 << 2)
73#define H_BLANK_INT (1 << 3)
74#define V_PULSE3_INT (1 << 4)
75#define SPI_BUSY_INT (1 << 7)
76#define WIN_A_UF_INT (1 << 8)
77#define WIN_B_UF_INT (1 << 9)
78#define WIN_C_UF_INT (1 << 10)
79#define MSF_INT (1 << 12)
80#define SSF_INT (1 << 13)
81#define WIN_A_OF_INT (1 << 14)
82#define WIN_B_OF_INT (1 << 15)
83#define WIN_C_OF_INT (1 << 16)
84#define GPIO_0_INT (1 << 18)
85#define GPIO_1_INT (1 << 19)
86#define GPIO_2_INT (1 << 20)
87
88#define DC_CMD_SIGNAL_RAISE1 0x03c
89#define DC_CMD_SIGNAL_RAISE2 0x03d
90#define DC_CMD_SIGNAL_RAISE3 0x03e
91#define DC_CMD_STATE_ACCESS 0x040
92#define READ_MUX_ASSEMBLY (0 << 0)
93#define READ_MUX_ACTIVE (1 << 0)
94#define WRITE_MUX_ASSEMBLY (0 << 2)
95#define WRITE_MUX_ACTIVE (1 << 2)
96
97#define DC_CMD_STATE_CONTROL 0x041
98#define GENERAL_ACT_REQ (1 << 0)
99#define WIN_A_ACT_REQ (1 << 1)
100#define WIN_B_ACT_REQ (1 << 2)
101#define WIN_C_ACT_REQ (1 << 3)
102#define GENERAL_UPDATE (1 << 8)
103#define WIN_A_UPDATE (1 << 9)
104#define WIN_B_UPDATE (1 << 10)
105#define WIN_C_UPDATE (1 << 11)
106#define NC_HOST_TRIG (1 << 24)
107
108#define DC_CMD_DISPLAY_WINDOW_HEADER 0x042
109#define WINDOW_A_SELECT (1 << 4)
110#define WINDOW_B_SELECT (1 << 5)
111#define WINDOW_C_SELECT (1 << 6)
112
113#define DC_CMD_REG_ACT_CONTROL 0x043
114
115#define DC_COM_CRC_CONTROL 0x300
116#define CRC_ALWAYS_ENABLE (1 << 3)
117#define CRC_ALWAYS_DISABLE (0 << 3)
118#define CRC_INPUT_DATA_ACTIVE_DATA (1 << 2)
119#define CRC_INPUT_DATA_FULL_FRAME (0 << 2)
120#define CRC_WAIT_TWO_VSYNC (1 << 1)
121#define CRC_WAIT_ONE_VSYNC (0 << 1)
122#define CRC_ENABLE_ENABLE (1 << 0)
123#define CRC_ENABLE_DISABLE (0 << 0)
124#define DC_COM_CRC_CHECKSUM 0x301
125#define DC_COM_PIN_OUTPUT_ENABLE0 0x302
126#define DC_COM_PIN_OUTPUT_ENABLE1 0x303
127#define DC_COM_PIN_OUTPUT_ENABLE2 0x304
128#define DC_COM_PIN_OUTPUT_ENABLE3 0x305
129#define PIN_OUTPUT_LSPI_OUTPUT_EN (1 << 8)
130#define PIN_OUTPUT_LSPI_OUTPUT_DIS (1 << 8)
131#define DC_COM_PIN_OUTPUT_POLARITY0 0x306
132
133#define DC_COM_PIN_OUTPUT_POLARITY1 0x307
134#define LHS_OUTPUT_POLARITY_LOW (1 << 30)
135#define LVS_OUTPUT_POLARITY_LOW (1 << 28)
136#define LSC0_OUTPUT_POLARITY_LOW (1 << 24)
137
138#define DC_COM_PIN_OUTPUT_POLARITY2 0x308
139
140#define DC_COM_PIN_OUTPUT_POLARITY3 0x309
141#define LSPI_OUTPUT_POLARITY_LOW (1 << 8)
142
143#define DC_COM_PIN_OUTPUT_DATA0 0x30a
144#define DC_COM_PIN_OUTPUT_DATA1 0x30b
145#define DC_COM_PIN_OUTPUT_DATA2 0x30c
146#define DC_COM_PIN_OUTPUT_DATA3 0x30d
147#define DC_COM_PIN_INPUT_ENABLE0 0x30e
148#define DC_COM_PIN_INPUT_ENABLE1 0x30f
149#define DC_COM_PIN_INPUT_ENABLE2 0x310
150#define DC_COM_PIN_INPUT_ENABLE3 0x311
151#define PIN_INPUT_LSPI_INPUT_EN (1 << 8)
152#define PIN_INPUT_LSPI_INPUT_DIS (1 << 8)
153#define DC_COM_PIN_INPUT_DATA0 0x312
154#define DC_COM_PIN_INPUT_DATA1 0x313
155#define DC_COM_PIN_OUTPUT_SELECT0 0x314
156#define DC_COM_PIN_OUTPUT_SELECT1 0x315
157#define DC_COM_PIN_OUTPUT_SELECT2 0x316
158#define DC_COM_PIN_OUTPUT_SELECT3 0x317
159#define DC_COM_PIN_OUTPUT_SELECT4 0x318
160#define DC_COM_PIN_OUTPUT_SELECT5 0x319
161#define DC_COM_PIN_OUTPUT_SELECT6 0x31a
162
163#define PIN5_LM1_LCD_M1_OUTPUT_MASK (7 << 4)
164#define PIN5_LM1_LCD_M1_OUTPUT_M1 (0 << 4)
165#define PIN5_LM1_LCD_M1_OUTPUT_LD21 (2 << 4)
166#define PIN5_LM1_LCD_M1_OUTPUT_PM1 (3 << 4)
167
168#define PIN1_LHS_OUTPUT (1 << 30)
169#define PIN1_LVS_OUTPUT (1 << 28)
170
171#define DC_COM_PIN_MISC_CONTROL 0x31b
172#define DC_COM_PM0_CONTROL 0x31c
173#define DC_COM_PM0_DUTY_CYCLE 0x31d
174#define DC_COM_PM1_CONTROL 0x31e
175#define DC_COM_PM1_DUTY_CYCLE 0x31f
176
177#define PM_PERIOD_SHIFT 18
178#define PM_CLK_DIVIDER_SHIFT 4
179
180#define DC_COM_SPI_CONTROL 0x320
181#define DC_COM_SPI_START_BYTE 0x321
182#define DC_COM_HSPI_WRITE_DATA_AB 0x322
183#define DC_COM_HSPI_WRITE_DATA_CD 0x323
184#define DC_COM_HSPI_CS_DC 0x324
185#define DC_COM_SCRATCH_REGISTER_A 0x325
186#define DC_COM_SCRATCH_REGISTER_B 0x326
187#define DC_COM_GPIO_CTRL 0x327
188#define DC_COM_GPIO_DEBOUNCE_COUNTER 0x328
189#define DC_COM_CRC_CHECKSUM_LATCHED 0x329
190
191#define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400
192#define H_PULSE_0_ENABLE (1 << 8)
193#define H_PULSE_1_ENABLE (1 << 10)
194#define H_PULSE_2_ENABLE (1 << 12)
195#define V_PULSE_0_ENABLE (1 << 16)
196#define V_PULSE_1_ENABLE (1 << 18)
197#define V_PULSE_2_ENABLE (1 << 19)
198#define V_PULSE_3_ENABLE (1 << 20)
199#define M0_ENABLE (1 << 24)
200#define M1_ENABLE (1 << 26)
201
202#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
203#define DI_ENABLE (1 << 16)
204#define PP_ENABLE (1 << 18)
205
206#define DC_DISP_DISP_WIN_OPTIONS 0x402
207#define CURSOR_ENABLE (1 << 16)
208#define TVO_ENABLE (1 << 28)
209#define DSI_ENABLE (1 << 29)
210#define HDMI_ENABLE (1 << 30)
211
212#define DC_DISP_MEM_HIGH_PRIORITY 0x403
213#define DC_DISP_MEM_HIGH_PRIORITY_TIMER 0x404
214#define DC_DISP_DISP_TIMING_OPTIONS 0x405
215#define VSYNC_H_POSITION(x) ((x) & 0xfff)
216
217#define DC_DISP_REF_TO_SYNC 0x406
218#define DC_DISP_SYNC_WIDTH 0x407
219#define DC_DISP_BACK_PORCH 0x408
220#define DC_DISP_DISP_ACTIVE 0x409
221#define DC_DISP_FRONT_PORCH 0x40a
222#define DC_DISP_H_PULSE0_CONTROL 0x40b
223#define DC_DISP_H_PULSE0_POSITION_A 0x40c
224#define DC_DISP_H_PULSE0_POSITION_B 0x40d
225#define DC_DISP_H_PULSE0_POSITION_C 0x40e
226#define DC_DISP_H_PULSE0_POSITION_D 0x40f
227#define DC_DISP_H_PULSE1_CONTROL 0x410
228#define DC_DISP_H_PULSE1_POSITION_A 0x411
229#define DC_DISP_H_PULSE1_POSITION_B 0x412
230#define DC_DISP_H_PULSE1_POSITION_C 0x413
231#define DC_DISP_H_PULSE1_POSITION_D 0x414
232#define DC_DISP_H_PULSE2_CONTROL 0x415
233#define DC_DISP_H_PULSE2_POSITION_A 0x416
234#define DC_DISP_H_PULSE2_POSITION_B 0x417
235#define DC_DISP_H_PULSE2_POSITION_C 0x418
236#define DC_DISP_H_PULSE2_POSITION_D 0x419
237#define DC_DISP_V_PULSE0_CONTROL 0x41a
238#define DC_DISP_V_PULSE0_POSITION_A 0x41b
239#define DC_DISP_V_PULSE0_POSITION_B 0x41c
240#define DC_DISP_V_PULSE0_POSITION_C 0x41d
241#define DC_DISP_V_PULSE1_CONTROL 0x41e
242#define DC_DISP_V_PULSE1_POSITION_A 0x41f
243#define DC_DISP_V_PULSE1_POSITION_B 0x420
244#define DC_DISP_V_PULSE1_POSITION_C 0x421
245#define DC_DISP_V_PULSE2_CONTROL 0x422
246#define DC_DISP_V_PULSE2_POSITION_A 0x423
247#define DC_DISP_V_PULSE3_CONTROL 0x424
248#define DC_DISP_V_PULSE3_POSITION_A 0x425
249#define DC_DISP_M0_CONTROL 0x426
250#define DC_DISP_M1_CONTROL 0x427
251#define DC_DISP_DI_CONTROL 0x428
252#define DC_DISP_PP_CONTROL 0x429
253#define DC_DISP_PP_SELECT_A 0x42a
254#define DC_DISP_PP_SELECT_B 0x42b
255#define DC_DISP_PP_SELECT_C 0x42c
256#define DC_DISP_PP_SELECT_D 0x42d
257
258#define PULSE_MODE_NORMAL (0 << 3)
259#define PULSE_MODE_ONE_CLOCK (1 << 3)
260#define PULSE_POLARITY_HIGH (0 << 4)
261#define PULSE_POLARITY_LOW (1 << 4)
262#define PULSE_QUAL_ALWAYS (0 << 6)
263#define PULSE_QUAL_VACTIVE (2 << 6)
264#define PULSE_QUAL_VACTIVE1 (3 << 6)
265#define PULSE_LAST_START_A (0 << 8)
266#define PULSE_LAST_END_A (1 << 8)
267#define PULSE_LAST_START_B (2 << 8)
268#define PULSE_LAST_END_B (3 << 8)
269#define PULSE_LAST_START_C (4 << 8)
270#define PULSE_LAST_END_C (5 << 8)
271#define PULSE_LAST_START_D (6 << 8)
272#define PULSE_LAST_END_D (7 << 8)
273
274#define PULSE_START(x) ((x) & 0xfff)
275#define PULSE_END(x) (((x) & 0xfff) << 16)
276
277#define DC_DISP_DISP_CLOCK_CONTROL 0x42e
278#define PIXEL_CLK_DIVIDER_PCD1 (0 << 8)
279#define PIXEL_CLK_DIVIDER_PCD1H (1 << 8)
280#define PIXEL_CLK_DIVIDER_PCD2 (2 << 8)
281#define PIXEL_CLK_DIVIDER_PCD3 (3 << 8)
282#define PIXEL_CLK_DIVIDER_PCD4 (4 << 8)
283#define PIXEL_CLK_DIVIDER_PCD6 (5 << 8)
284#define PIXEL_CLK_DIVIDER_PCD8 (6 << 8)
285#define PIXEL_CLK_DIVIDER_PCD9 (7 << 8)
286#define PIXEL_CLK_DIVIDER_PCD12 (8 << 8)
287#define PIXEL_CLK_DIVIDER_PCD16 (9 << 8)
288#define PIXEL_CLK_DIVIDER_PCD18 (10 << 8)
289#define PIXEL_CLK_DIVIDER_PCD24 (11 << 8)
290#define PIXEL_CLK_DIVIDER_PCD13 (12 << 8)
291#define SHIFT_CLK_DIVIDER(x) ((x) & 0xff)
292
293#define DC_DISP_DISP_INTERFACE_CONTROL 0x42f
294#define DISP_DATA_FORMAT_DF1P1C (0 << 0)
295#define DISP_DATA_FORMAT_DF1P2C24B (1 << 0)
296#define DISP_DATA_FORMAT_DF1P2C18B (2 << 0)
297#define DISP_DATA_FORMAT_DF1P2C16B (3 << 0)
298#define DISP_DATA_FORMAT_DF2S (5 << 0)
299#define DISP_DATA_FORMAT_DF3S (6 << 0)
300#define DISP_DATA_FORMAT_DFSPI (7 << 0)
301#define DISP_DATA_FORMAT_DF1P3C24B (8 << 0)
302#define DISP_DATA_FORMAT_DF1P3C18B (9 << 0)
303#define DISP_DATA_ALIGNMENT_MSB (0 << 8)
304#define DISP_DATA_ALIGNMENT_LSB (1 << 8)
305#define DISP_DATA_ORDER_RED_BLUE (0 << 9)
306#define DISP_DATA_ORDER_BLUE_RED (1 << 9)
307
308#define DC_DISP_DISP_COLOR_CONTROL 0x430
309#define BASE_COLOR_SIZE666 (0 << 0)
310#define BASE_COLOR_SIZE111 (1 << 0)
311#define BASE_COLOR_SIZE222 (2 << 0)
312#define BASE_COLOR_SIZE333 (3 << 0)
313#define BASE_COLOR_SIZE444 (4 << 0)
314#define BASE_COLOR_SIZE555 (5 << 0)
315#define BASE_COLOR_SIZE565 (6 << 0)
316#define BASE_COLOR_SIZE332 (7 << 0)
317#define BASE_COLOR_SIZE888 (8 << 0)
318
319#define DITHER_CONTROL_DISABLE (0 << 8)
320#define DITHER_CONTROL_ORDERED (2 << 8)
321#define DITHER_CONTROL_ERRDIFF (3 << 8)
322
323#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
324#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
325#define DE_SELECT_ACTIVE_BLANK 0x0
326#define DE_SELECT_ACTIVE 0x1
327#define DE_SELECT_ACTIVE_IS 0x2
328#define DE_CONTROL_ONECLK (0 << 2)
329#define DE_CONTROL_NORMAL (1 << 2)
330#define DE_CONTROL_EARLY_EXT (2 << 2)
331#define DE_CONTROL_EARLY (3 << 2)
332#define DE_CONTROL_ACTIVE_BLANK (4 << 2)
333
334#define DC_DISP_SERIAL_INTERFACE_OPTIONS 0x433
335#define DC_DISP_LCD_SPI_OPTIONS 0x434
336#define DC_DISP_BORDER_COLOR 0x435
337#define DC_DISP_COLOR_KEY0_LOWER 0x436
338#define DC_DISP_COLOR_KEY0_UPPER 0x437
339#define DC_DISP_COLOR_KEY1_LOWER 0x438
340#define DC_DISP_COLOR_KEY1_UPPER 0x439
341
342#define DC_DISP_CURSOR_FOREGROUND 0x43c
343#define DC_DISP_CURSOR_BACKGROUND 0x43d
344#define CURSOR_COLOR(_r, _g, _b) ((_r) | ((_g) << 8) | ((_b) << 16))
345
346#define DC_DISP_CURSOR_START_ADDR 0x43e
347#define DC_DISP_CURSOR_START_ADDR_NS 0x43f
348#define CURSOR_START_ADDR_MASK (((1 << 22) - 1) << 10)
349#define CURSOR_START_ADDR(_addr) ((_addr) >> 10)
350#define CURSOR_SIZE_64 (1 << 24)
351
352#define DC_DISP_CURSOR_POSITION 0x440
353#define CURSOR_POSITION(_x, _y) \
354 (((_x) & ((1 << 16) - 1)) | \
355 (((_y) & ((1 << 16) - 1)) << 16))
356
357#define DC_DISP_CURSOR_POSITION_NS 0x441
358#define DC_DISP_INIT_SEQ_CONTROL 0x442
359#define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443
360#define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444
361#define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445
362#define DC_DISP_SPI_INIT_SEQ_DATA_D 0x446
363#define DC_DISP_DC_MCCIF_FIFOCTRL 0x480
364#define DC_DISP_MCCIF_DISPLAY0A_HYST 0x481
365#define DC_DISP_MCCIF_DISPLAY0B_HYST 0x482
366#define DC_DISP_MCCIF_DISPLAY0C_HYST 0x483
367#define DC_DISP_MCCIF_DISPLAY1B_HYST 0x484
368#define DC_DISP_DAC_CRT_CTRL 0x4c0
369#define DC_DISP_DISP_MISC_CONTROL 0x4c1
370
371#define DC_WIN_COLOR_PALETTE(x) (0x500 + (x))
372
373#define DC_WIN_PALETTE_COLOR_EXT 0x600
374#define DC_WIN_H_FILTER_P(x) (0x601 + (x))
375#define DC_WIN_CSC_YOF 0x611
376#define DC_WIN_CSC_KYRGB 0x612
377#define DC_WIN_CSC_KUR 0x613
378#define DC_WIN_CSC_KVR 0x614
379#define DC_WIN_CSC_KUG 0x615
380#define DC_WIN_CSC_KVG 0x616
381#define DC_WIN_CSC_KUB 0x617
382#define DC_WIN_CSC_KVB 0x618
383#define DC_WIN_V_FILTER_P(x) (0x619 + (x))
384#define DC_WIN_WIN_OPTIONS 0x700
385#define H_DIRECTION_INCREMENT (0 << 0)
386#define H_DIRECTION_DECREMENT (1 << 0)
387#define V_DIRECTION_INCREMENT (0 << 2)
388#define V_DIRECTION_DECREMENT (1 << 2)
389#define COLOR_EXPAND (1 << 6)
390#define H_FILTER_ENABLE (1 << 8)
391#define V_FILTER_ENABLE (1 << 10)
392#define CP_ENABLE (1 << 16)
393#define CSC_ENABLE (1 << 18)
394#define DV_ENABLE (1 << 20)
395#define WIN_ENABLE (1 << 30)
396
397#define DC_WIN_BYTE_SWAP 0x701
398#define BYTE_SWAP_NOSWAP 0
399#define BYTE_SWAP_SWAP2 1
400#define BYTE_SWAP_SWAP4 2
401#define BYTE_SWAP_SWAP4HW 3
402
403#define DC_WIN_BUFFER_CONTROL 0x702
404#define BUFFER_CONTROL_HOST 0
405#define BUFFER_CONTROL_VI 1
406#define BUFFER_CONTROL_EPP 2
407#define BUFFER_CONTROL_MPEGE 3
408#define BUFFER_CONTROL_SB2D 4
409
410#define DC_WIN_COLOR_DEPTH 0x703
411
412#define DC_WIN_POSITION 0x704
413#define H_POSITION(x) (((x) & 0xfff) << 0)
414#define V_POSITION(x) (((x) & 0xfff) << 16)
415
416#define DC_WIN_SIZE 0x705
417#define H_SIZE(x) (((x) & 0xfff) << 0)
418#define V_SIZE(x) (((x) & 0xfff) << 16)
419
420#define DC_WIN_PRESCALED_SIZE 0x706
421#define H_PRESCALED_SIZE(x) (((x) & 0x3fff) << 0)
422#define V_PRESCALED_SIZE(x) (((x) & 0xfff) << 16)
423
424#define DC_WIN_H_INITIAL_DDA 0x707
425#define DC_WIN_V_INITIAL_DDA 0x708
426#define DC_WIN_DDA_INCREMENT 0x709
427#define H_DDA_INC(x) (((x) & 0xffff) << 0)
428#define V_DDA_INC(x) (((x) & 0xffff) << 16)
429
430#define DC_WIN_LINE_STRIDE 0x70a
431#define LINE_STRIDE(x) (x)
432#define UV_LINE_STRIDE(x) (((x) & 0xffff) << 16)
433#define DC_WIN_BUF_STRIDE 0x70b
434#define DC_WIN_UV_BUF_STRIDE 0x70c
435#define DC_WIN_BUFFER_ADDR_MODE 0x70d
436#define DC_WIN_BUFFER_ADDR_MODE_LINEAR (0 << 0)
437#define DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV (0 << 16)
438#define DC_WIN_BUFFER_ADDR_MODE_TILE (1 << 0)
439#define DC_WIN_BUFFER_ADDR_MODE_TILE_UV (1 << 16)
440#define DC_WIN_DV_CONTROL 0x70e
441#define DC_WIN_BLEND_NOKEY 0x70f
442#define DC_WIN_BLEND_1WIN 0x710
443#define DC_WIN_BLEND_2WIN_X 0x711
444#define DC_WIN_BLEND_2WIN_Y 0x712
445#define DC_WIN_BLEND_3WIN_XY 0x713
446#define CKEY_NOKEY (0 << 0)
447#define CKEY_KEY0 (1 << 0)
448#define CKEY_KEY1 (2 << 0)
449#define CKEY_KEY01 (3 << 0)
450#define BLEND_CONTROL_FIX (0 << 2)
451#define BLEND_CONTROL_ALPHA (1 << 2)
452#define BLEND_CONTROL_DEPENDANT (2 << 2)
453#define BLEND_CONTROL_PREMULT (3 << 2)
454#define BLEND_WEIGHT0(x) (((x) & 0xff) << 8)
455#define BLEND_WEIGHT1(x) (((x) & 0xff) << 16)
456#define BLEND(key, control, weight0, weight1) \
457 (CKEY_ ## key | BLEND_CONTROL_ ## control | \
458 BLEND_WEIGHT0(weight0) | BLEND_WEIGHT1(weight1))
459
460
461#define DC_WIN_HP_FETCH_CONTROL 0x714
462#define DC_WINBUF_START_ADDR 0x800
463#define DC_WINBUF_START_ADDR_NS 0x801
464#define DC_WINBUF_START_ADDR_U 0x802
465#define DC_WINBUF_START_ADDR_U_NS 0x803
466#define DC_WINBUF_START_ADDR_V 0x804
467#define DC_WINBUF_START_ADDR_V_NS 0x805
468#define DC_WINBUF_ADDR_H_OFFSET 0x806
469#define DC_WINBUF_ADDR_H_OFFSET_NS 0x807
470#define DC_WINBUF_ADDR_V_OFFSET 0x808
471#define DC_WINBUF_ADDR_V_OFFSET_NS 0x809
472#define DC_WINBUF_UFLOW_STATUS 0x80a
473
474/* direct versions of DC_WINBUF_UFLOW_STATUS */
475#define DC_WINBUF_AD_UFLOW_STATUS 0xbca
476#define DC_WINBUF_BD_UFLOW_STATUS 0xdca
477#define DC_WINBUF_CD_UFLOW_STATUS 0xfca
478
479#define DC_DISP_SD_CONTROL 0x4c2
480#define SD_ENABLE_NORMAL (1 << 0)
481#define SD_ENABLE_ONESHOT (2 << 0)
482#define SD_USE_VID_LUMA (1 << 2)
483#define SD_BIN_WIDTH_ONE (0 << 3)
484#define SD_BIN_WIDTH_TWO (1 << 3)
485#define SD_BIN_WIDTH_FOUR (2 << 3)
486#define SD_BIN_WIDTH_EIGHT (3 << 3)
487#define SD_BIN_WIDTH_MASK (3 << 3)
488#define SD_AGGRESSIVENESS(x) (((x) & 0x7) << 5)
489#define SD_HW_UPDATE_DLY(x) (((x) & 0x3) << 8)
490#define SD_ONESHOT_ENABLE (1 << 10)
491#define SD_CORRECTION_MODE_AUTO (0 << 11)
492#define SD_CORRECTION_MODE_MAN (1 << 11)
493
494#define NUM_BIN_WIDTHS 4
495#define STEPS_PER_AGG_LVL 64
496#define STEPS_PER_AGG_CHG_LOG2 5
497#define STEPS_PER_AGG_CHG (1<<STEPS_PER_AGG_CHG_LOG2)
498#define ADJ_PHASE_STEP 8
499#define K_STEP 4
500
501#define DC_DISP_SD_CSC_COEFF 0x4c3
502#define SD_CSC_COEFF_R(x) (((x) & 0xf) << 4)
503#define SD_CSC_COEFF_G(x) (((x) & 0xf) << 12)
504#define SD_CSC_COEFF_B(x) (((x) & 0xf) << 20)
505
506#define DC_DISP_SD_LUT(i) (0x4c4 + i)
507#define DC_DISP_SD_LUT_NUM 9
508#define SD_LUT_R(x) (((x) & 0xff) << 0)
509#define SD_LUT_G(x) (((x) & 0xff) << 8)
510#define SD_LUT_B(x) (((x) & 0xff) << 16)
511
512#define DC_DISP_SD_FLICKER_CONTROL 0x4cd
513#define SD_FC_TIME_LIMIT(x) (((x) & 0xff) << 0)
514#define SD_FC_THRESHOLD(x) (((x) & 0xff) << 8)
515
516#define DC_DISP_SD_PIXEL_COUNT 0x4ce
517
518#define DC_DISP_SD_HISTOGRAM(i) (0x4cf + i)
519#define DC_DISP_SD_HISTOGRAM_NUM 8
520#define SD_HISTOGRAM_BIN_0(val) (((val) & (0xff << 0)) >> 0)
521#define SD_HISTOGRAM_BIN_1(val) (((val) & (0xff << 8)) >> 8)
522#define SD_HISTOGRAM_BIN_2(val) (((val) & (0xff << 16)) >> 16)
523#define SD_HISTOGRAM_BIN_3(val) (((val) & (0xff << 24)) >> 24)
524
525#define DC_DISP_SD_BL_PARAMETERS 0x4d7
526#define SD_BLP_TIME_CONSTANT(x) (((x) & 0x7ff) << 0)
527#define SD_BLP_STEP(x) (((x) & 0xff) << 16)
528
529#define DC_DISP_SD_BL_TF(i) (0x4d8 + i)
530#define DC_DISP_SD_BL_TF_NUM 4
531#define SD_BL_TF_POINT_0(x) (((x) & 0xff) << 0)
532#define SD_BL_TF_POINT_1(x) (((x) & 0xff) << 8)
533#define SD_BL_TF_POINT_2(x) (((x) & 0xff) << 16)
534#define SD_BL_TF_POINT_3(x) (((x) & 0xff) << 24)
535
536#define DC_DISP_SD_BL_CONTROL 0x4dc
537#define SD_BLC_MODE_MAN (0 << 0)
538#define SD_BLC_MODE_AUTO (1 << 1)
539#define SD_BLC_BRIGHTNESS(val) (((val) & (0xff << 8)) >> 8)
540
541#define DC_DISP_SD_HW_K_VALUES 0x4dd
542#define SD_HW_K_R(val) (((val) & (0x3ff << 0)) >> 0)
543#define SD_HW_K_G(val) (((val) & (0x3ff << 10)) >> 10)
544#define SD_HW_K_B(val) (((val) & (0x3ff << 20)) >> 20)
545
546#define DC_DISP_SD_MAN_K_VALUES 0x4de
547#define SD_MAN_K_R(x) (((x) & 0x3ff) << 0)
548#define SD_MAN_K_G(x) (((x) & 0x3ff) << 10)
549#define SD_MAN_K_B(x) (((x) & 0x3ff) << 20)
550
551#define NUM_AGG_PRI_LVLS 4
552#define SD_AGG_PRI_LVL(x) ((x) >> 3)
553#define SD_GET_AGG(x) ((x) & 0x7)
554
555#endif
diff --git a/drivers/video/tegra/dc/dc_sysfs.c b/drivers/video/tegra/dc/dc_sysfs.c
new file mode 100644
index 00000000000..6bb18382e6e
--- /dev/null
+++ b/drivers/video/tegra/dc/dc_sysfs.c
@@ -0,0 +1,327 @@
1/*
2 * drivers/video/tegra/dc/dc_sysfs.c
3 *
4 * Copyright (c) 2011, NVIDIA Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include <linux/platform_device.h>
22#include <linux/kernel.h>
23
24#include <mach/dc.h>
25#include <mach/fb.h>
26
27#include "dc_reg.h"
28#include "dc_priv.h"
29#include "nvsd.h"
30
31static ssize_t mode_show(struct device *device,
32 struct device_attribute *attr, char *buf)
33{
34 struct nvhost_device *ndev = to_nvhost_device(device);
35 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
36 struct tegra_dc_mode *m;
37 ssize_t res;
38
39 mutex_lock(&dc->lock);
40 m = &dc->mode;
41 res = snprintf(buf, PAGE_SIZE,
42 "pclk: %d\n"
43 "h_ref_to_sync: %d\n"
44 "v_ref_to_sync: %d\n"
45 "h_sync_width: %d\n"
46 "v_sync_width: %d\n"
47 "h_back_porch: %d\n"
48 "v_back_porch: %d\n"
49 "h_active: %d\n"
50 "v_active: %d\n"
51 "h_front_porch: %d\n"
52 "v_front_porch: %d\n"
53 "stereo_mode: %d\n",
54 m->pclk, m->h_ref_to_sync, m->v_ref_to_sync,
55 m->h_sync_width, m->v_sync_width,
56 m->h_back_porch, m->v_back_porch,
57 m->h_active, m->v_active,
58 m->h_front_porch, m->v_front_porch,
59 m->stereo_mode);
60 mutex_unlock(&dc->lock);
61
62 return res;
63}
64
65static DEVICE_ATTR(mode, S_IRUGO, mode_show, NULL);
66
67static ssize_t stats_enable_show(struct device *dev,
68 struct device_attribute *attr, char *buf)
69{
70 struct nvhost_device *ndev = to_nvhost_device(dev);
71 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
72 bool enabled;
73
74 if (mutex_lock_killable(&dc->lock))
75 return -EINTR;
76 enabled = tegra_dc_stats_get(dc);
77 mutex_unlock(&dc->lock);
78
79 return snprintf(buf, PAGE_SIZE, "%d", enabled);
80}
81
82static ssize_t stats_enable_store(struct device *dev,
83 struct device_attribute *attr, const char *buf, size_t count)
84{
85 struct nvhost_device *ndev = to_nvhost_device(dev);
86 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
87 unsigned long val = 0;
88
89 if (strict_strtoul(buf, 10, &val) < 0)
90 return -EINVAL;
91
92 if (mutex_lock_killable(&dc->lock))
93 return -EINTR;
94 tegra_dc_stats_enable(dc, !!val);
95 mutex_unlock(&dc->lock);
96
97 return count;
98}
99
100static DEVICE_ATTR(stats_enable, S_IRUGO|S_IWUSR,
101 stats_enable_show, stats_enable_store);
102
103static ssize_t enable_show(struct device *device,
104 struct device_attribute *attr, char *buf)
105{
106 struct nvhost_device *ndev = to_nvhost_device(device);
107 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
108 ssize_t res;
109
110 mutex_lock(&dc->lock);
111 res = snprintf(buf, PAGE_SIZE, "%d\n", dc->enabled);
112 mutex_unlock(&dc->lock);
113 return res;
114}
115
116static ssize_t enable_store(struct device *dev,
117 struct device_attribute *attr, const char *buf, size_t count)
118{
119 struct nvhost_device *ndev = to_nvhost_device(dev);
120 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
121 unsigned long val = 0;
122
123 if (strict_strtoul(buf, 10, &val) < 0)
124 return -EINVAL;
125
126 if (val) {
127 tegra_dc_enable(dc);
128 } else {
129 tegra_dc_disable(dc);
130 }
131
132 return count;
133}
134
135static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, enable_show, enable_store);
136
137static ssize_t crc_checksum_latched_show(struct device *device,
138 struct device_attribute *attr, char *buf)
139{
140 struct nvhost_device *ndev = to_nvhost_device(device);
141 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
142
143 u32 crc;
144
145 if (!dc->enabled) {
146 dev_err(&dc->ndev->dev, "Failed to get dc.\n");
147 return -EFAULT;
148 }
149
150 crc = tegra_dc_read_checksum_latched(dc);
151
152 return snprintf(buf, PAGE_SIZE, "%u", crc);
153}
154
155static ssize_t crc_checksum_latched_store(struct device *dev,
156 struct device_attribute *attr, const char *buf, size_t count)
157{
158 struct nvhost_device *ndev = to_nvhost_device(dev);
159 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
160 unsigned long val = 0;
161
162 if (!dc->enabled) {
163 dev_err(&dc->ndev->dev, "Failed to get dc.\n");
164 return -EFAULT;
165 }
166
167 if (strict_strtoul(buf, 10, &val) < 0)
168 return -EINVAL;
169
170 if (val == 1) {
171 tegra_dc_enable_crc(dc);
172 dev_err(&dc->ndev->dev, "crc is enabled.\n");
173 } else if (val == 0) {
174 tegra_dc_disable_crc(dc);
175 dev_err(&dc->ndev->dev, "crc is disabled.\n");
176 } else
177 dev_err(&dc->ndev->dev, "Invalid input.\n");
178
179 return count;
180}
181static DEVICE_ATTR(crc_checksum_latched, S_IRUGO|S_IWUSR,
182 crc_checksum_latched_show, crc_checksum_latched_store);
183
184#define ORIENTATION_PORTRAIT "portrait"
185#define ORIENTATION_LANDSCAPE "landscape"
186
187static ssize_t orientation_3d_show(struct device *dev,
188 struct device_attribute *attr, char *buf)
189{
190 struct nvhost_device *ndev = to_nvhost_device(dev);
191 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
192 struct tegra_dc_out *dc_out = dc->out;
193 const char *orientation;
194 switch (dc_out->stereo->orientation) {
195 case TEGRA_DC_STEREO_LANDSCAPE:
196 orientation = ORIENTATION_LANDSCAPE;
197 break;
198 case TEGRA_DC_STEREO_PORTRAIT:
199 orientation = ORIENTATION_PORTRAIT;
200 break;
201 default:
202 pr_err("Invalid value is stored for stereo_orientation.\n");
203 return -EINVAL;
204 }
205 return snprintf(buf, PAGE_SIZE, "%s\n", orientation);
206}
207
208static ssize_t orientation_3d_store(struct device *dev,
209 struct device_attribute *attr, const char *buf, size_t cnt)
210{
211 struct nvhost_device *ndev = to_nvhost_device(dev);
212 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
213 struct tegra_dc_out *dc_out = dc->out;
214 struct tegra_stereo_out *stereo = dc_out->stereo;
215 int orientation;
216
217 if (0 == strncmp(buf, ORIENTATION_PORTRAIT,
218 min(cnt, ARRAY_SIZE(ORIENTATION_PORTRAIT) - 1))) {
219 orientation = TEGRA_DC_STEREO_PORTRAIT;
220 } else if (0 == strncmp(buf, ORIENTATION_LANDSCAPE,
221 min(cnt, ARRAY_SIZE(ORIENTATION_LANDSCAPE) - 1))) {
222 orientation = TEGRA_DC_STEREO_LANDSCAPE;
223 } else {
224 pr_err("Invalid property value for stereo_orientation.\n");
225 return -EINVAL;
226 }
227 stereo->orientation = orientation;
228 stereo->set_orientation(orientation);
229 return cnt;
230}
231
232static DEVICE_ATTR(stereo_orientation,
233 S_IRUGO|S_IWUSR, orientation_3d_show, orientation_3d_store);
234
235#define MODE_2D "2d"
236#define MODE_3D "3d"
237
238static ssize_t mode_3d_show(struct device *dev,
239 struct device_attribute *attr, char *buf)
240{
241 struct nvhost_device *ndev = to_nvhost_device(dev);
242 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
243 struct tegra_dc_out *dc_out = dc->out;
244 const char *mode;
245 switch (dc_out->stereo->mode_2d_3d) {
246 case TEGRA_DC_STEREO_MODE_2D:
247 mode = MODE_2D;
248 break;
249 case TEGRA_DC_STEREO_MODE_3D:
250 mode = MODE_3D;
251 break;
252 default:
253 pr_err("Invalid value is stored for stereo_mode.\n");
254 return -EINVAL;
255 }
256 return snprintf(buf, PAGE_SIZE, "%s\n", mode);
257}
258
259static ssize_t mode_3d_store(struct device *dev,
260 struct device_attribute *attr, const char *buf, size_t cnt)
261{
262 struct nvhost_device *ndev = to_nvhost_device(dev);
263 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
264 struct tegra_dc_out *dc_out = dc->out;
265 struct tegra_stereo_out *stereo = dc_out->stereo;
266 int mode;
267
268 if (0 == strncmp(buf, MODE_2D, min(cnt, ARRAY_SIZE(MODE_2D) - 1))) {
269 mode = TEGRA_DC_STEREO_MODE_2D;
270 } else if (0 == strncmp(buf, MODE_3D,
271 min(cnt, ARRAY_SIZE(MODE_3D) - 1))) {
272 mode = TEGRA_DC_STEREO_MODE_3D;
273 } else {
274 pr_err("Invalid property value for stereo_mode.\n");
275 return -EINVAL;
276 }
277 stereo->mode_2d_3d = mode;
278 stereo->set_mode(mode);
279 return cnt;
280}
281
282static DEVICE_ATTR(stereo_mode,
283 S_IRUGO|S_IWUSR, mode_3d_show, mode_3d_store);
284
285void __devexit tegra_dc_remove_sysfs(struct device *dev)
286{
287 struct nvhost_device *ndev = to_nvhost_device(dev);
288 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
289 struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings;
290
291 device_remove_file(dev, &dev_attr_mode);
292 device_remove_file(dev, &dev_attr_enable);
293 device_remove_file(dev, &dev_attr_stats_enable);
294 device_remove_file(dev, &dev_attr_crc_checksum_latched);
295
296 if (dc->out->stereo) {
297 device_remove_file(dev, &dev_attr_stereo_orientation);
298 device_remove_file(dev, &dev_attr_stereo_mode);
299 }
300
301 if (sd_settings)
302 nvsd_remove_sysfs(dev);
303}
304
305void tegra_dc_create_sysfs(struct device *dev)
306{
307 struct nvhost_device *ndev = to_nvhost_device(dev);
308 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
309 struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings;
310 int error = 0;
311
312 error |= device_create_file(dev, &dev_attr_mode);
313 error |= device_create_file(dev, &dev_attr_enable);
314 error |= device_create_file(dev, &dev_attr_stats_enable);
315 error |= device_create_file(dev, &dev_attr_crc_checksum_latched);
316
317 if (dc->out->stereo) {
318 error |= device_create_file(dev, &dev_attr_stereo_orientation);
319 error |= device_create_file(dev, &dev_attr_stereo_mode);
320 }
321
322 if (sd_settings)
323 error |= nvsd_create_sysfs(dev);
324
325 if (error)
326 dev_err(&ndev->dev, "Failed to create sysfs attributes!\n");
327}
diff --git a/drivers/video/tegra/dc/dsi.c b/drivers/video/tegra/dc/dsi.c
new file mode 100644
index 00000000000..c33d6e0a58b
--- /dev/null
+++ b/drivers/video/tegra/dc/dsi.c
@@ -0,0 +1,3042 @@
1/*
2 * drivers/video/tegra/dc/dsi.c
3 *
4 * Copyright (c) 2011, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/err.h>
20#include <linux/fb.h>
21#include <linux/gpio.h>
22#include <linux/interrupt.h>
23#include <linux/kernel.h>
24#include <linux/slab.h>
25#include <linux/spinlock.h>
26#include <linux/workqueue.h>
27
28#include <mach/clk.h>
29#include <mach/dc.h>
30#include <mach/fb.h>
31#include <mach/csi.h>
32#include <linux/nvhost.h>
33
34#include "dc_reg.h"
35#include "dc_priv.h"
36#include "dsi_regs.h"
37#include "dsi.h"
38
39#define DSI_USE_SYNC_POINTS 1
40#define S_TO_MS(x) (1000 * (x))
41
42#define DSI_MODULE_NOT_INIT 0x0
43#define DSI_MODULE_INIT 0x1
44
45#define DSI_LPHS_NOT_INIT 0x0
46#define DSI_LPHS_IN_LP_MODE 0x1
47#define DSI_LPHS_IN_HS_MODE 0x2
48
49#define DSI_VIDEO_TYPE_NOT_INIT 0x0
50#define DSI_VIDEO_TYPE_VIDEO_MODE 0x1
51#define DSI_VIDEO_TYPE_CMD_MODE 0x2
52
53#define DSI_DRIVEN_MODE_NOT_INIT 0x0
54#define DSI_DRIVEN_MODE_DC 0x1
55#define DSI_DRIVEN_MODE_HOST 0x2
56
57#define DSI_PHYCLK_OUT_DIS 0x0
58#define DSI_PHYCLK_OUT_EN 0x1
59
60#define DSI_PHYCLK_NOT_INIT 0x0
61#define DSI_PHYCLK_CONTINUOUS 0x1
62#define DSI_PHYCLK_TX_ONLY 0x2
63
64#define DSI_CLK_BURST_NOT_INIT 0x0
65#define DSI_CLK_BURST_NONE_BURST 0x1
66#define DSI_CLK_BURST_BURST_MODE 0x2
67
68#define DSI_DC_STREAM_DISABLE 0x0
69#define DSI_DC_STREAM_ENABLE 0x1
70
71#define DSI_LP_OP_NOT_INIT 0x0
72#define DSI_LP_OP_WRITE 0x1
73#define DSI_LP_OP_READ 0x2
74
75static bool enable_read_debug;
76module_param(enable_read_debug, bool, 0644);
77MODULE_PARM_DESC(enable_read_debug,
78 "Enable to print read fifo and return packet type");
79
80struct dsi_status {
81 unsigned init:2;
82
83 unsigned lphs:2;
84
85 unsigned vtype:2;
86 unsigned driven:2;
87
88 unsigned clk_out:2;
89 unsigned clk_mode:2;
90 unsigned clk_burst:2;
91
92 unsigned lp_op:2;
93
94 unsigned dc_stream:1;
95};
96
97/* source of video data */
98enum {
99 TEGRA_DSI_DRIVEN_BY_DC,
100 TEGRA_DSI_DRIVEN_BY_HOST,
101};
102
103struct tegra_dc_dsi_data {
104 struct tegra_dc *dc;
105 void __iomem *base;
106 struct resource *base_res;
107
108 struct clk *dc_clk;
109 struct clk *dsi_clk;
110 bool clk_ref;
111
112 struct mutex lock;
113
114 /* data from board info */
115 struct tegra_dsi_out info;
116
117 struct dsi_status status;
118
119 struct dsi_phy_timing_inclk phy_timing;
120
121 u8 driven_mode;
122 u8 controller_index;
123
124 u8 pixel_scaler_mul;
125 u8 pixel_scaler_div;
126
127 u32 default_shift_clk_div;
128 u32 default_pixel_clk_khz;
129 u32 default_hs_clk_khz;
130
131 u32 shift_clk_div;
132 u32 target_hs_clk_khz;
133 u32 target_lp_clk_khz;
134
135 u32 syncpt_id;
136 u32 syncpt_val;
137
138 u16 current_bit_clk_ns;
139 u32 current_dsi_clk_khz;
140
141 u32 dsi_control_val;
142
143 bool ulpm;
144 bool enabled;
145};
146
147const u32 dsi_pkt_seq_reg[NUMOF_PKT_SEQ] = {
148 DSI_PKT_SEQ_0_LO,
149 DSI_PKT_SEQ_0_HI,
150 DSI_PKT_SEQ_1_LO,
151 DSI_PKT_SEQ_1_HI,
152 DSI_PKT_SEQ_2_LO,
153 DSI_PKT_SEQ_2_HI,
154 DSI_PKT_SEQ_3_LO,
155 DSI_PKT_SEQ_3_HI,
156 DSI_PKT_SEQ_4_LO,
157 DSI_PKT_SEQ_4_HI,
158 DSI_PKT_SEQ_5_LO,
159 DSI_PKT_SEQ_5_HI,
160};
161
162const u32 dsi_pkt_seq_video_non_burst_syne[NUMOF_PKT_SEQ] = {
163 PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
164 0,
165 PKT_ID0(CMD_VE) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
166 0,
167 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
168 0,
169 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(1) |
170 PKT_ID2(CMD_HE) | PKT_LEN2(0),
171 PKT_ID3(CMD_BLNK) | PKT_LEN3(2) | PKT_ID4(CMD_RGB) | PKT_LEN4(3) |
172 PKT_ID5(CMD_BLNK) | PKT_LEN5(4),
173 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
174 0,
175 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(1) |
176 PKT_ID2(CMD_HE) | PKT_LEN2(0),
177 PKT_ID3(CMD_BLNK) | PKT_LEN3(2) | PKT_ID4(CMD_RGB) | PKT_LEN4(3) |
178 PKT_ID5(CMD_BLNK) | PKT_LEN5(4),
179};
180
181const u32 dsi_pkt_seq_video_non_burst[NUMOF_PKT_SEQ] = {
182 PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
183 0,
184 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
185 0,
186 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
187 0,
188 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2) |
189 PKT_ID2(CMD_RGB) | PKT_LEN2(3),
190 PKT_ID3(CMD_BLNK) | PKT_LEN3(4),
191 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
192 0,
193 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2) |
194 PKT_ID2(CMD_RGB) | PKT_LEN2(3),
195 PKT_ID3(CMD_BLNK) | PKT_LEN3(4),
196};
197
198static const u32 dsi_pkt_seq_video_burst[NUMOF_PKT_SEQ] = {
199 PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP,
200 0,
201 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP,
202 0,
203 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP,
204 0,
205 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)|
206 PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP,
207 PKT_ID0(CMD_EOT) | PKT_LEN0(7),
208 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(7) | PKT_LP,
209 0,
210 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)|
211 PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP,
212 PKT_ID0(CMD_EOT) | PKT_LEN0(7),
213};
214
215static const u32 dsi_pkt_seq_video_burst_no_eot[NUMOF_PKT_SEQ] = {
216 PKT_ID0(CMD_VS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
217 0,
218 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
219 0,
220 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
221 0,
222 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)|
223 PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP,
224 PKT_ID0(CMD_EOT) | PKT_LEN0(0),
225 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_EOT) | PKT_LEN1(0) | PKT_LP,
226 0,
227 PKT_ID0(CMD_HS) | PKT_LEN0(0) | PKT_ID1(CMD_BLNK) | PKT_LEN1(2)|
228 PKT_ID2(CMD_RGB) | PKT_LEN2(3) | PKT_LP,
229 PKT_ID0(CMD_EOT) | PKT_LEN0(0),
230};
231
232/* TODO: verify with hw about this format */
233const u32 dsi_pkt_seq_cmd_mode[NUMOF_PKT_SEQ] = {
234 0,
235 0,
236 0,
237 0,
238 0,
239 0,
240 PKT_ID0(CMD_LONGW) | PKT_LEN0(3) | PKT_ID1(CMD_EOT) | PKT_LEN1(7),
241 0,
242 0,
243 0,
244 PKT_ID0(CMD_LONGW) | PKT_LEN0(3) | PKT_ID1(CMD_EOT) | PKT_LEN1(7),
245 0,
246};
247
248const u32 init_reg[] = {
249 DSI_INT_ENABLE,
250 DSI_INT_STATUS,
251 DSI_INT_MASK,
252 DSI_INIT_SEQ_DATA_0,
253 DSI_INIT_SEQ_DATA_1,
254 DSI_INIT_SEQ_DATA_2,
255 DSI_INIT_SEQ_DATA_3,
256 DSI_INIT_SEQ_DATA_4,
257 DSI_INIT_SEQ_DATA_5,
258 DSI_INIT_SEQ_DATA_6,
259 DSI_INIT_SEQ_DATA_7,
260 DSI_DCS_CMDS,
261 DSI_PKT_SEQ_0_LO,
262 DSI_PKT_SEQ_1_LO,
263 DSI_PKT_SEQ_2_LO,
264 DSI_PKT_SEQ_3_LO,
265 DSI_PKT_SEQ_4_LO,
266 DSI_PKT_SEQ_5_LO,
267 DSI_PKT_SEQ_0_HI,
268 DSI_PKT_SEQ_1_HI,
269 DSI_PKT_SEQ_2_HI,
270 DSI_PKT_SEQ_3_HI,
271 DSI_PKT_SEQ_4_HI,
272 DSI_PKT_SEQ_5_HI,
273 DSI_CONTROL,
274 DSI_HOST_DSI_CONTROL,
275 DSI_PAD_CONTROL,
276 DSI_PAD_CONTROL_CD,
277 DSI_SOL_DELAY,
278 DSI_MAX_THRESHOLD,
279 DSI_TRIGGER,
280 DSI_TX_CRC,
281 DSI_INIT_SEQ_CONTROL,
282 DSI_PKT_LEN_0_1,
283 DSI_PKT_LEN_2_3,
284 DSI_PKT_LEN_4_5,
285 DSI_PKT_LEN_6_7,
286};
287
288inline unsigned long tegra_dsi_readl(struct tegra_dc_dsi_data *dsi, u32 reg)
289{
290 BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
291 return readl(dsi->base + reg * 4);
292}
293EXPORT_SYMBOL(tegra_dsi_readl);
294
295inline void tegra_dsi_writel(struct tegra_dc_dsi_data *dsi, u32 val, u32 reg)
296{
297 BUG_ON(!nvhost_module_powered(nvhost_get_host(dsi->dc->ndev)->dev));
298 writel(val, dsi->base + reg * 4);
299}
300EXPORT_SYMBOL(tegra_dsi_writel);
301
302static int tegra_dsi_syncpt(struct tegra_dc_dsi_data *dsi)
303{
304 u32 val;
305 int ret;
306
307 ret = 0;
308
309 dsi->syncpt_val = nvhost_syncpt_read(
310 &nvhost_get_host(dsi->dc->ndev)->syncpt,
311 dsi->syncpt_id);
312
313 val = DSI_INCR_SYNCPT_COND(OP_DONE) |
314 DSI_INCR_SYNCPT_INDX(dsi->syncpt_id);
315 tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT);
316
317 /* TODO: Use interrupt rather than polling */
318 ret = nvhost_syncpt_wait(&nvhost_get_host(dsi->dc->ndev)->syncpt,
319 dsi->syncpt_id, dsi->syncpt_val + 1);
320 if (ret < 0) {
321 dev_err(&dsi->dc->ndev->dev, "DSI sync point failure\n");
322 goto fail;
323 }
324
325 (dsi->syncpt_val)++;
326 return 0;
327fail:
328 return ret;
329}
330
331static u32 tegra_dsi_get_hs_clk_rate(struct tegra_dc_dsi_data *dsi)
332{
333 u32 dsi_clock_rate_khz;
334
335 switch (dsi->info.video_burst_mode) {
336 case TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED:
337 case TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED:
338 case TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED:
339 case TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED:
340 /* Calculate DSI HS clock rate for DSI burst mode */
341 dsi_clock_rate_khz = dsi->default_pixel_clk_khz *
342 dsi->shift_clk_div;
343 break;
344 case TEGRA_DSI_VIDEO_NONE_BURST_MODE:
345 case TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END:
346 case TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED:
347 default:
348 /* Clock rate is default DSI clock rate for non-burst mode */
349 dsi_clock_rate_khz = dsi->default_hs_clk_khz;
350 break;
351 }
352
353 return dsi_clock_rate_khz;
354}
355
356static u32 tegra_dsi_get_lp_clk_rate(struct tegra_dc_dsi_data *dsi, u8 lp_op)
357{
358 u32 dsi_clock_rate_khz;
359
360 if (dsi->info.enable_hs_clock_on_lp_cmd_mode)
361 if (dsi->info.hs_clk_in_lp_cmd_mode_freq_khz)
362 dsi_clock_rate_khz =
363 dsi->info.hs_clk_in_lp_cmd_mode_freq_khz;
364 else
365 dsi_clock_rate_khz = tegra_dsi_get_hs_clk_rate(dsi);
366 else
367 if (lp_op == DSI_LP_OP_READ)
368 dsi_clock_rate_khz =
369 dsi->info.lp_read_cmd_mode_freq_khz;
370 else
371 dsi_clock_rate_khz =
372 dsi->info.lp_cmd_mode_freq_khz;
373
374 return dsi_clock_rate_khz;
375}
376
377static u32 tegra_dsi_get_shift_clk_div(struct tegra_dc_dsi_data *dsi)
378{
379 u32 shift_clk_div;
380 u32 max_shift_clk_div;
381 u32 burst_width;
382 u32 burst_width_max;
383
384 /* Get the real value of default shift_clk_div. default_shift_clk_div
385 * holds the real value of shift_clk_div.
386 */
387 shift_clk_div = dsi->default_shift_clk_div;
388
389 /* Calculate shift_clk_div which can matche the video_burst_mode. */
390 if (dsi->info.video_burst_mode >=
391 TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED) {
392 /* The max_shift_clk_div is multiplied by 10 to save the
393 * fraction
394 */
395 if (dsi->info.max_panel_freq_khz >= dsi->default_hs_clk_khz)
396 max_shift_clk_div = dsi->info.max_panel_freq_khz
397 * shift_clk_div * 10 / dsi->default_hs_clk_khz;
398 else
399 max_shift_clk_div = shift_clk_div * 10;
400
401 burst_width = dsi->info.video_burst_mode
402 - TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED;
403 burst_width_max = TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED
404 - TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED;
405
406 shift_clk_div = (max_shift_clk_div - shift_clk_div * 10) *
407 burst_width / (burst_width_max * 10) + shift_clk_div;
408 }
409
410 return shift_clk_div;
411}
412
413static void tegra_dsi_init_sw(struct tegra_dc *dc,
414 struct tegra_dc_dsi_data *dsi)
415{
416 u32 h_width_pixels;
417 u32 v_width_lines;
418 u32 pixel_clk_hz;
419 u32 byte_clk_hz;
420 u32 plld_clk_mhz;
421
422 switch (dsi->info.pixel_format) {
423 case TEGRA_DSI_PIXEL_FORMAT_16BIT_P:
424 /* 2 bytes per pixel */
425 dsi->pixel_scaler_mul = 2;
426 dsi->pixel_scaler_div = 1;
427 break;
428 case TEGRA_DSI_PIXEL_FORMAT_18BIT_P:
429 /* 2.25 bytes per pixel */
430 dsi->pixel_scaler_mul = 9;
431 dsi->pixel_scaler_div = 4;
432 break;
433 case TEGRA_DSI_PIXEL_FORMAT_18BIT_NP:
434 case TEGRA_DSI_PIXEL_FORMAT_24BIT_P:
435 /* 3 bytes per pixel */
436 dsi->pixel_scaler_mul = 3;
437 dsi->pixel_scaler_div = 1;
438 break;
439 default:
440 break;
441 }
442
443 dsi->controller_index = dc->ndev->id;
444 dsi->ulpm = false;
445 dsi->enabled = false;
446 dsi->clk_ref = false;
447
448 dsi->dsi_control_val =
449 DSI_CONTROL_VIRTUAL_CHANNEL(dsi->info.virtual_channel) |
450 DSI_CONTROL_NUM_DATA_LANES(dsi->info.n_data_lanes - 1) |
451 DSI_CONTROL_VID_SOURCE(dsi->controller_index) |
452 DSI_CONTROL_DATA_FORMAT(dsi->info.pixel_format);
453
454 /* Below we are going to calculate dsi and dc clock rate.
455 * Calcuate the horizontal and vertical width.
456 */
457 h_width_pixels = dc->mode.h_back_porch + dc->mode.h_front_porch +
458 dc->mode.h_sync_width + dc->mode.h_active;
459 v_width_lines = dc->mode.v_back_porch + dc->mode.v_front_porch +
460 dc->mode.v_sync_width + dc->mode.v_active;
461
462 /* Calculate minimum required pixel rate. */
463 pixel_clk_hz = h_width_pixels * v_width_lines * dsi->info.refresh_rate;
464 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
465 if (dsi->info.rated_refresh_rate >= dsi->info.refresh_rate)
466 dev_info(&dc->ndev->dev, "DSI: measured refresh rate "
467 "should be larger than rated refresh rate.\n");
468 dc->mode.rated_pclk = h_width_pixels * v_width_lines *
469 dsi->info.rated_refresh_rate;
470 }
471
472 /* Calculate minimum byte rate on DSI interface. */
473 byte_clk_hz = (pixel_clk_hz * dsi->pixel_scaler_mul) /
474 (dsi->pixel_scaler_div * dsi->info.n_data_lanes);
475
476 /* Round up to multiple of mega hz. */
477 plld_clk_mhz = DIV_ROUND_UP((byte_clk_hz * NUMOF_BIT_PER_BYTE),
478 1000000);
479
480 /* Calculate default real shift_clk_div. */
481 dsi->default_shift_clk_div = (NUMOF_BIT_PER_BYTE / 2) *
482 dsi->pixel_scaler_mul / (dsi->pixel_scaler_div *
483 dsi->info.n_data_lanes);
484 /* Calculate default DSI hs clock. DSI interface is double data rate.
485 * Data is transferred on both rising and falling edge of clk, div by 2
486 * to get the actual clock rate.
487 */
488 dsi->default_hs_clk_khz = plld_clk_mhz * 1000 / 2;
489 dsi->default_pixel_clk_khz = plld_clk_mhz * 1000 / 2
490 / dsi->default_shift_clk_div;
491
492 /* Get the actual shift_clk_div and clock rates. */
493 dsi->shift_clk_div = tegra_dsi_get_shift_clk_div(dsi);
494 dsi->target_lp_clk_khz =
495 tegra_dsi_get_lp_clk_rate(dsi, DSI_LP_OP_WRITE);
496 dsi->target_hs_clk_khz = tegra_dsi_get_hs_clk_rate(dsi);
497
498 dev_info(&dc->ndev->dev, "DSI: HS clock rate is %d\n",
499 dsi->target_hs_clk_khz);
500
501 dsi->controller_index = dc->ndev->id;
502
503#if DSI_USE_SYNC_POINTS
504 dsi->syncpt_id = NVSYNCPT_DSI;
505#endif
506
507 /*
508 * Force video clock to be continuous mode if
509 * enable_hs_clock_on_lp_cmd_mode is set
510 */
511 if (dsi->info.enable_hs_clock_on_lp_cmd_mode) {
512 if (dsi->info.video_clock_mode !=
513 TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS)
514 dev_warn(&dc->ndev->dev,
515 "Force clock continuous mode\n");
516
517 dsi->info.video_clock_mode = TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS;
518 }
519
520}
521
522#define SELECT_T_PHY(platform_t_phy_ns, default_phy, clk_ns, hw_inc) ( \
523(platform_t_phy_ns) ? ( \
524((DSI_CONVERT_T_PHY_NS_TO_T_PHY(platform_t_phy_ns, clk_ns, hw_inc)) < 0 ? 0 : \
525(DSI_CONVERT_T_PHY_NS_TO_T_PHY(platform_t_phy_ns, clk_ns, hw_inc)))) : \
526((default_phy) < 0 ? 0 : (default_phy)))
527
528static void tegra_dsi_get_clk_phy_timing(struct tegra_dc_dsi_data *dsi,
529 struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
530{
531 phy_timing_clk->t_tlpx = SELECT_T_PHY(
532 dsi->info.phy_timing.t_tlpx_ns,
533 T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC);
534
535 phy_timing_clk->t_clktrail = SELECT_T_PHY(
536 dsi->info.phy_timing.t_clktrail_ns,
537 T_CLKTRAIL_DEFAULT(clk_ns), clk_ns, T_CLKTRAIL_HW_INC);
538
539 phy_timing_clk->t_clkpost = SELECT_T_PHY(
540 dsi->info.phy_timing.t_clkpost_ns,
541 T_CLKPOST_DEFAULT(clk_ns), clk_ns, T_CLKPOST_HW_INC);
542
543 phy_timing_clk->t_clkzero = SELECT_T_PHY(
544 dsi->info.phy_timing.t_clkzero_ns,
545 T_CLKZERO_DEFAULT(clk_ns), clk_ns, T_CLKZERO_HW_INC);
546
547 phy_timing_clk->t_clkprepare = SELECT_T_PHY(
548 dsi->info.phy_timing.t_clkprepare_ns,
549 T_CLKPREPARE_DEFAULT(clk_ns), clk_ns, T_CLKPREPARE_HW_INC);
550
551 phy_timing_clk->t_clkpre = SELECT_T_PHY(
552 dsi->info.phy_timing.t_clkpre_ns,
553 T_CLKPRE_DEFAULT, clk_ns, T_CLKPRE_HW_INC);
554}
555
556static void tegra_dsi_get_hs_phy_timing(struct tegra_dc_dsi_data *dsi,
557 struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
558{
559 phy_timing_clk->t_tlpx = SELECT_T_PHY(
560 dsi->info.phy_timing.t_tlpx_ns,
561 T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC);
562
563 phy_timing_clk->t_hsdexit = SELECT_T_PHY(
564 dsi->info.phy_timing.t_hsdexit_ns,
565 T_HSEXIT_DEFAULT(clk_ns), clk_ns, T_HSEXIT_HW_INC);
566
567 phy_timing_clk->t_hstrail = SELECT_T_PHY(
568 dsi->info.phy_timing.t_hstrail_ns,
569 T_HSTRAIL_DEFAULT(clk_ns), clk_ns, T_HSTRAIL_HW_INC);
570
571 phy_timing_clk->t_datzero = SELECT_T_PHY(
572 dsi->info.phy_timing.t_datzero_ns,
573 T_DATZERO_DEFAULT(clk_ns), clk_ns, T_DATZERO_HW_INC);
574
575 phy_timing_clk->t_hsprepare = SELECT_T_PHY(
576 dsi->info.phy_timing.t_hsprepare_ns,
577 T_HSPREPARE_DEFAULT(clk_ns), clk_ns, T_HSPREPARE_HW_INC);
578}
579
580static void tegra_dsi_get_escape_phy_timing(struct tegra_dc_dsi_data *dsi,
581 struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
582{
583 phy_timing_clk->t_tlpx = SELECT_T_PHY(
584 dsi->info.phy_timing.t_tlpx_ns,
585 T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC);
586}
587
588static void tegra_dsi_get_bta_phy_timing(struct tegra_dc_dsi_data *dsi,
589 struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
590{
591 phy_timing_clk->t_tlpx = SELECT_T_PHY(
592 dsi->info.phy_timing.t_tlpx_ns,
593 T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC);
594
595 phy_timing_clk->t_taget = SELECT_T_PHY(
596 dsi->info.phy_timing.t_taget_ns,
597 T_TAGET_DEFAULT(clk_ns), clk_ns, T_TAGET_HW_INC);
598
599 phy_timing_clk->t_tasure = SELECT_T_PHY(
600 dsi->info.phy_timing.t_tasure_ns,
601 T_TASURE_DEFAULT(clk_ns), clk_ns, T_TASURE_HW_INC);
602
603 phy_timing_clk->t_tago = SELECT_T_PHY(
604 dsi->info.phy_timing.t_tago_ns,
605 T_TAGO_DEFAULT(clk_ns), clk_ns, T_TAGO_HW_INC);
606}
607
608static void tegra_dsi_get_ulps_phy_timing(struct tegra_dc_dsi_data *dsi,
609 struct dsi_phy_timing_inclk *phy_timing_clk, u32 clk_ns)
610{
611 phy_timing_clk->t_tlpx = SELECT_T_PHY(
612 dsi->info.phy_timing.t_tlpx_ns,
613 T_TLPX_DEFAULT(clk_ns), clk_ns, T_TLPX_HW_INC);
614
615 phy_timing_clk->t_wakeup = SELECT_T_PHY(
616 dsi->info.phy_timing.t_wakeup_ns,
617 T_WAKEUP_DEFAULT, clk_ns, T_WAKEUP_HW_INC);
618}
619
620#undef SELECT_T_PHY
621
622static void tegra_dsi_get_phy_timing(struct tegra_dc_dsi_data *dsi,
623 struct dsi_phy_timing_inclk *phy_timing_clk,
624 u32 clk_ns, u8 lphs)
625{
626 if (lphs == DSI_LPHS_IN_HS_MODE) {
627 tegra_dsi_get_clk_phy_timing(dsi, phy_timing_clk, clk_ns);
628 tegra_dsi_get_hs_phy_timing(dsi, phy_timing_clk, clk_ns);
629 } else {
630 /* default is LP mode */
631 tegra_dsi_get_escape_phy_timing(dsi, phy_timing_clk, clk_ns);
632 tegra_dsi_get_bta_phy_timing(dsi, phy_timing_clk, clk_ns);
633 tegra_dsi_get_ulps_phy_timing(dsi, phy_timing_clk, clk_ns);
634 if (dsi->info.enable_hs_clock_on_lp_cmd_mode)
635 tegra_dsi_get_clk_phy_timing
636 (dsi, phy_timing_clk, clk_ns);
637 }
638}
639
640static int tegra_dsi_mipi_phy_timing_range(struct tegra_dc_dsi_data *dsi,
641 struct dsi_phy_timing_inclk *phy_timing,
642 u32 clk_ns, u8 lphs)
643{
644#define CHECK_RANGE(val, min, max) ( \
645 ((min) == NOT_DEFINED ? 0 : (val) < (min)) || \
646 ((max) == NOT_DEFINED ? 0 : (val) > (max)) ? -EINVAL : 0)
647
648 int err = 0;
649
650 err = CHECK_RANGE(
651 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
652 phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC),
653 MIPI_T_TLPX_NS_MIN, MIPI_T_TLPX_NS_MAX);
654 if (err < 0) {
655 dev_warn(&dsi->dc->ndev->dev,
656 "dsi: Tlpx mipi range violated\n");
657 goto fail;
658 }
659
660 if (lphs == DSI_LPHS_IN_HS_MODE) {
661 err = CHECK_RANGE(
662 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
663 phy_timing->t_hsdexit, clk_ns, T_HSEXIT_HW_INC),
664 MIPI_T_HSEXIT_NS_MIN, MIPI_T_HSEXIT_NS_MAX);
665 if (err < 0) {
666 dev_warn(&dsi->dc->ndev->dev,
667 "dsi: HsExit mipi range violated\n");
668 goto fail;
669 }
670
671 err = CHECK_RANGE(
672 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
673 phy_timing->t_hstrail, clk_ns, T_HSTRAIL_HW_INC),
674 MIPI_T_HSTRAIL_NS_MIN(clk_ns), MIPI_T_HSTRAIL_NS_MAX);
675 if (err < 0) {
676 dev_warn(&dsi->dc->ndev->dev,
677 "dsi: HsTrail mipi range violated\n");
678 goto fail;
679 }
680
681 err = CHECK_RANGE(
682 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
683 phy_timing->t_datzero, clk_ns, T_DATZERO_HW_INC),
684 MIPI_T_HSZERO_NS_MIN, MIPI_T_HSZERO_NS_MAX);
685 if (err < 0) {
686 dev_warn(&dsi->dc->ndev->dev,
687 "dsi: HsZero mipi range violated\n");
688 goto fail;
689 }
690
691 err = CHECK_RANGE(
692 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
693 phy_timing->t_hsprepare, clk_ns, T_HSPREPARE_HW_INC),
694 MIPI_T_HSPREPARE_NS_MIN(clk_ns),
695 MIPI_T_HSPREPARE_NS_MAX(clk_ns));
696 if (err < 0) {
697 dev_warn(&dsi->dc->ndev->dev,
698 "dsi: HsPrepare mipi range violated\n");
699 goto fail;
700 }
701
702 err = CHECK_RANGE(
703 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
704 phy_timing->t_hsprepare, clk_ns, T_HSPREPARE_HW_INC) +
705 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
706 phy_timing->t_datzero, clk_ns, T_DATZERO_HW_INC),
707 MIPI_T_HSPREPARE_ADD_HSZERO_NS_MIN(clk_ns),
708 MIPI_T_HSPREPARE_ADD_HSZERO_NS_MAX);
709 if (err < 0) {
710 dev_warn(&dsi->dc->ndev->dev,
711 "dsi: HsPrepare + HsZero mipi range violated\n");
712 goto fail;
713 }
714 } else {
715 /* default is LP mode */
716 err = CHECK_RANGE(
717 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
718 phy_timing->t_wakeup, clk_ns, T_WAKEUP_HW_INC),
719 MIPI_T_WAKEUP_NS_MIN, MIPI_T_WAKEUP_NS_MAX);
720 if (err < 0) {
721 dev_warn(&dsi->dc->ndev->dev,
722 "dsi: WakeUp mipi range violated\n");
723 goto fail;
724 }
725
726 err = CHECK_RANGE(
727 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
728 phy_timing->t_tasure, clk_ns, T_TASURE_HW_INC),
729 MIPI_T_TASURE_NS_MIN(DSI_CONVERT_T_PHY_TO_T_PHY_NS(
730 phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC)),
731 MIPI_T_TASURE_NS_MAX(DSI_CONVERT_T_PHY_TO_T_PHY_NS(
732 phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC)));
733 if (err < 0) {
734 dev_warn(&dsi->dc->ndev->dev,
735 "dsi: TaSure mipi range violated\n");
736 goto fail;
737 }
738 }
739
740 if (lphs == DSI_LPHS_IN_HS_MODE ||
741 dsi->info.enable_hs_clock_on_lp_cmd_mode) {
742 err = CHECK_RANGE(
743 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
744 phy_timing->t_clktrail, clk_ns, T_CLKTRAIL_HW_INC),
745 MIPI_T_CLKTRAIL_NS_MIN, MIPI_T_CLKTRAIL_NS_MAX);
746 if (err < 0) {
747 dev_warn(&dsi->dc->ndev->dev,
748 "dsi: ClkTrail mipi range violated\n");
749 goto fail;
750 }
751
752 err = CHECK_RANGE(
753 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
754 phy_timing->t_clkpost, clk_ns, T_CLKPOST_HW_INC),
755 MIPI_T_CLKPOST_NS_MIN(clk_ns), MIPI_T_CLKPOST_NS_MAX);
756 if (err < 0) {
757 dev_warn(&dsi->dc->ndev->dev,
758 "dsi: ClkPost mipi range violated\n");
759 goto fail;
760 }
761
762 err = CHECK_RANGE(
763 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
764 phy_timing->t_clkzero, clk_ns, T_CLKZERO_HW_INC),
765 MIPI_T_CLKZERO_NS_MIN, MIPI_T_CLKZERO_NS_MAX);
766 if (err < 0) {
767 dev_warn(&dsi->dc->ndev->dev,
768 "dsi: ClkZero mipi range violated\n");
769 goto fail;
770 }
771
772 err = CHECK_RANGE(
773 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
774 phy_timing->t_clkprepare, clk_ns, T_CLKPREPARE_HW_INC),
775 MIPI_T_CLKPREPARE_NS_MIN, MIPI_T_CLKPREPARE_NS_MAX);
776 if (err < 0) {
777 dev_warn(&dsi->dc->ndev->dev,
778 "dsi: ClkPrepare mipi range violated\n");
779 goto fail;
780 }
781
782 err = CHECK_RANGE(
783 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
784 phy_timing->t_clkpre, clk_ns, T_CLKPRE_HW_INC),
785 MIPI_T_CLKPRE_NS_MIN, MIPI_T_CLKPRE_NS_MAX);
786 if (err < 0) {
787 dev_warn(&dsi->dc->ndev->dev,
788 "dsi: ClkPre mipi range violated\n");
789 goto fail;
790 }
791
792 err = CHECK_RANGE(
793 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
794 phy_timing->t_clkprepare, clk_ns, T_CLKPREPARE_HW_INC) +
795 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
796 phy_timing->t_clkzero, clk_ns, T_CLKZERO_HW_INC),
797 MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MIN,
798 MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MAX);
799 if (err < 0) {
800 dev_warn(&dsi->dc->ndev->dev,
801 "dsi: ClkPrepare + ClkZero mipi range violated\n");
802 goto fail;
803 }
804 }
805fail:
806#undef CHECK_RANGE
807 return err;
808}
809
810static int tegra_dsi_hs_phy_len(struct tegra_dc_dsi_data *dsi,
811 struct dsi_phy_timing_inclk *phy_timing,
812 u32 clk_ns, u8 lphs)
813{
814 u32 hs_t_phy_ns;
815 u32 clk_t_phy_ns;
816 u32 t_phy_ns;
817 u32 h_blank_ns;
818 struct tegra_dc_mode *modes;
819 u32 t_pix_ns;
820 int err = 0;
821
822 if (!(lphs == DSI_LPHS_IN_HS_MODE))
823 goto fail;
824
825 modes = dsi->dc->out->modes;
826 t_pix_ns = clk_ns * BITS_PER_BYTE *
827 dsi->pixel_scaler_mul / dsi->pixel_scaler_div;
828
829 hs_t_phy_ns =
830 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
831 phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC) +
832 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
833 phy_timing->t_hsprepare, clk_ns, T_HSPREPARE_HW_INC) +
834 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
835 phy_timing->t_datzero, clk_ns, T_DATZERO_HW_INC) +
836 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
837 phy_timing->t_hstrail, clk_ns, T_HSTRAIL_HW_INC) +
838 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
839 phy_timing->t_hsdexit, clk_ns, T_HSEXIT_HW_INC);
840
841 clk_t_phy_ns =
842 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
843 phy_timing->t_clkpost, clk_ns, T_CLKPOST_HW_INC) +
844 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
845 phy_timing->t_clktrail, clk_ns, T_CLKTRAIL_HW_INC) +
846 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
847 phy_timing->t_hsdexit, clk_ns, T_HSEXIT_HW_INC) +
848 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
849 phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC) +
850 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
851 phy_timing->t_clkprepare, clk_ns, T_CLKPREPARE_HW_INC) +
852 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
853 phy_timing->t_clkzero, clk_ns, T_CLKZERO_HW_INC) +
854 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
855 phy_timing->t_clkpre, clk_ns, T_CLKPRE_HW_INC);
856
857 h_blank_ns = t_pix_ns * (modes->h_sync_width + modes->h_back_porch +
858 modes->h_front_porch);
859
860 /* Extra tlpx and byte cycle required by dsi HW */
861 t_phy_ns = dsi->info.n_data_lanes * (hs_t_phy_ns + clk_t_phy_ns +
862 DSI_CONVERT_T_PHY_TO_T_PHY_NS(
863 phy_timing->t_tlpx, clk_ns, T_TLPX_HW_INC) +
864 clk_ns * BITS_PER_BYTE);
865
866 if (h_blank_ns < t_phy_ns) {
867 err = -EINVAL;
868 dev_err(&dsi->dc->ndev->dev,
869 "dsi: Hblank is smaller than HS trans phy timing\n");
870 goto fail;
871 }
872
873 return 0;
874fail:
875 return err;
876}
877
878static int tegra_dsi_constraint_phy_timing(struct tegra_dc_dsi_data *dsi,
879 struct dsi_phy_timing_inclk *phy_timing,
880 u32 clk_ns, u8 lphs)
881{
882 int err = 0;
883
884 err = tegra_dsi_mipi_phy_timing_range(dsi, phy_timing, clk_ns, lphs);
885 if (err < 0) {
886 dev_warn(&dsi->dc->ndev->dev, "dsi: mipi range violated\n");
887 goto fail;
888 }
889
890 err = tegra_dsi_hs_phy_len(dsi, phy_timing, clk_ns, lphs);
891 if (err < 0) {
892 dev_err(&dsi->dc->ndev->dev, "dsi: Hblank too short\n");
893 goto fail;
894 }
895
896 /* TODO: add more contraints */
897fail:
898 return err;
899}
900
901static void tegra_dsi_set_phy_timing(struct tegra_dc_dsi_data *dsi, u8 lphs)
902{
903 u32 val;
904 struct dsi_phy_timing_inclk phy_timing = dsi->phy_timing;
905
906 tegra_dsi_get_phy_timing
907 (dsi, &phy_timing, dsi->current_bit_clk_ns, lphs);
908
909 tegra_dsi_constraint_phy_timing(dsi, &phy_timing,
910 dsi->current_bit_clk_ns, lphs);
911
912 val = DSI_PHY_TIMING_0_THSDEXIT(phy_timing.t_hsdexit) |
913 DSI_PHY_TIMING_0_THSTRAIL(phy_timing.t_hstrail) |
914 DSI_PHY_TIMING_0_TDATZERO(phy_timing.t_datzero) |
915 DSI_PHY_TIMING_0_THSPREPR(phy_timing.t_hsprepare);
916 tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_0);
917
918 val = DSI_PHY_TIMING_1_TCLKTRAIL(phy_timing.t_clktrail) |
919 DSI_PHY_TIMING_1_TCLKPOST(phy_timing.t_clkpost) |
920 DSI_PHY_TIMING_1_TCLKZERO(phy_timing.t_clkzero) |
921 DSI_PHY_TIMING_1_TTLPX(phy_timing.t_tlpx);
922 tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_1);
923
924 val = DSI_PHY_TIMING_2_TCLKPREPARE(phy_timing.t_clkprepare) |
925 DSI_PHY_TIMING_2_TCLKPRE(phy_timing.t_clkpre) |
926 DSI_PHY_TIMING_2_TWAKEUP(phy_timing.t_wakeup);
927 tegra_dsi_writel(dsi, val, DSI_PHY_TIMING_2);
928
929 val = DSI_BTA_TIMING_TTAGET(phy_timing.t_taget) |
930 DSI_BTA_TIMING_TTASURE(phy_timing.t_tasure) |
931 DSI_BTA_TIMING_TTAGO(phy_timing.t_tago);
932 tegra_dsi_writel(dsi, val, DSI_BTA_TIMING);
933
934 dsi->phy_timing = phy_timing;
935}
936
937static u32 tegra_dsi_sol_delay_burst(struct tegra_dc *dc,
938 struct tegra_dc_dsi_data *dsi)
939{
940 u32 dsi_to_pixel_clk_ratio;
941 u32 temp;
942 u32 temp1;
943 u32 mipi_clk_adj_kHz;
944 u32 sol_delay;
945 struct tegra_dc_mode *dc_modes = &dc->mode;
946
947 /* Get Fdsi/Fpixel ration (note: Fdsi is in bit format) */
948 dsi_to_pixel_clk_ratio = (dsi->current_dsi_clk_khz * 2 +
949 dsi->default_pixel_clk_khz - 1) / dsi->default_pixel_clk_khz;
950
951 /* Convert Fdsi to byte format */
952 dsi_to_pixel_clk_ratio *= 1000/8;
953
954 /* Multiplying by 1000 so that we don't loose the fraction part */
955 temp = dc_modes->h_active * 1000;
956 temp1 = dc_modes->h_active + dc_modes->h_back_porch +
957 dc_modes->h_sync_width;
958
959 sol_delay = temp1 * dsi_to_pixel_clk_ratio -
960 temp * dsi->pixel_scaler_mul /
961 (dsi->pixel_scaler_div * dsi->info.n_data_lanes);
962
963 /* Do rounding on sol delay */
964 sol_delay = (sol_delay + 1000 - 1)/1000;
965
966 /* TODO:
967 * 1. find out the correct sol fifo depth to use
968 * 2. verify with hw about the clamping function
969 */
970 if (sol_delay > (480 * 4)) {
971 sol_delay = (480 * 4);
972 mipi_clk_adj_kHz = sol_delay +
973 (dc_modes->h_active * dsi->pixel_scaler_mul) /
974 (dsi->info.n_data_lanes * dsi->pixel_scaler_div);
975
976 mipi_clk_adj_kHz *= (dsi->default_pixel_clk_khz / temp1);
977
978 mipi_clk_adj_kHz *= 4;
979 }
980
981 dsi->target_hs_clk_khz = mipi_clk_adj_kHz;
982
983 return sol_delay;
984}
985
986static void tegra_dsi_set_sol_delay(struct tegra_dc *dc,
987 struct tegra_dc_dsi_data *dsi)
988{
989 u32 sol_delay;
990
991 if (dsi->info.video_burst_mode == TEGRA_DSI_VIDEO_NONE_BURST_MODE ||
992 dsi->info.video_burst_mode ==
993 TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END) {
994#define VIDEO_FIFO_LATENCY_PIXEL_CLK 8
995 sol_delay = VIDEO_FIFO_LATENCY_PIXEL_CLK *
996 dsi->pixel_scaler_mul / dsi->pixel_scaler_div;
997#undef VIDEO_FIFO_LATENCY_PIXEL_CLK
998 dsi->status.clk_burst = DSI_CLK_BURST_NONE_BURST;
999 } else {
1000 sol_delay = tegra_dsi_sol_delay_burst(dc, dsi);
1001 dsi->status.clk_burst = DSI_CLK_BURST_BURST_MODE;
1002 }
1003
1004 tegra_dsi_writel(dsi, DSI_SOL_DELAY_SOL_DELAY(sol_delay),
1005 DSI_SOL_DELAY);
1006}
1007
1008static void tegra_dsi_set_timeout(struct tegra_dc_dsi_data *dsi)
1009{
1010 u32 val;
1011 u32 bytes_per_frame;
1012 u32 timeout = 0;
1013
1014 /* TODO: verify the following equation */
1015 bytes_per_frame = dsi->current_dsi_clk_khz * 1000 * 2 /
1016 (dsi->info.refresh_rate * 8);
1017 timeout = bytes_per_frame / DSI_CYCLE_COUNTER_VALUE;
1018 timeout = (timeout + DSI_HTX_TO_MARGIN) & 0xffff;
1019
1020 val = DSI_TIMEOUT_0_LRXH_TO(DSI_LRXH_TO_VALUE) |
1021 DSI_TIMEOUT_0_HTX_TO(timeout);
1022 tegra_dsi_writel(dsi, val, DSI_TIMEOUT_0);
1023
1024 if (dsi->info.panel_reset_timeout_msec)
1025 timeout = (dsi->info.panel_reset_timeout_msec * 1000*1000)
1026 / dsi->current_bit_clk_ns;
1027 else
1028 timeout = DSI_PR_TO_VALUE;
1029
1030 val = DSI_TIMEOUT_1_PR_TO(timeout) |
1031 DSI_TIMEOUT_1_TA_TO(DSI_TA_TO_VALUE);
1032 tegra_dsi_writel(dsi, val, DSI_TIMEOUT_1);
1033
1034 val = DSI_TO_TALLY_P_RESET_STATUS(IN_RESET) |
1035 DSI_TO_TALLY_TA_TALLY(DSI_TA_TALLY_VALUE)|
1036 DSI_TO_TALLY_LRXH_TALLY(DSI_LRXH_TALLY_VALUE)|
1037 DSI_TO_TALLY_HTX_TALLY(DSI_HTX_TALLY_VALUE);
1038 tegra_dsi_writel(dsi, val, DSI_TO_TALLY);
1039}
1040
1041static void tegra_dsi_setup_video_mode_pkt_length(struct tegra_dc *dc,
1042 struct tegra_dc_dsi_data *dsi)
1043{
1044 u32 val;
1045 u32 hact_pkt_len;
1046 u32 hsa_pkt_len;
1047 u32 hbp_pkt_len;
1048 u32 hfp_pkt_len;
1049
1050 hact_pkt_len = dc->mode.h_active * dsi->pixel_scaler_mul /
1051 dsi->pixel_scaler_div;
1052 hsa_pkt_len = dc->mode.h_sync_width * dsi->pixel_scaler_mul /
1053 dsi->pixel_scaler_div;
1054 hbp_pkt_len = dc->mode.h_back_porch * dsi->pixel_scaler_mul /
1055 dsi->pixel_scaler_div;
1056 hfp_pkt_len = dc->mode.h_front_porch * dsi->pixel_scaler_mul /
1057 dsi->pixel_scaler_div;
1058
1059 if (dsi->info.video_burst_mode !=
1060 TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END)
1061 hbp_pkt_len += hsa_pkt_len;
1062
1063 hsa_pkt_len -= DSI_HSYNC_BLNK_PKT_OVERHEAD;
1064 hbp_pkt_len -= DSI_HBACK_PORCH_PKT_OVERHEAD;
1065 hfp_pkt_len -= DSI_HFRONT_PORCH_PKT_OVERHEAD;
1066
1067 val = DSI_PKT_LEN_0_1_LENGTH_0(0) |
1068 DSI_PKT_LEN_0_1_LENGTH_1(hsa_pkt_len);
1069 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_0_1);
1070
1071 val = DSI_PKT_LEN_2_3_LENGTH_2(hbp_pkt_len) |
1072 DSI_PKT_LEN_2_3_LENGTH_3(hact_pkt_len);
1073 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_2_3);
1074
1075 val = DSI_PKT_LEN_4_5_LENGTH_4(hfp_pkt_len) |
1076 DSI_PKT_LEN_4_5_LENGTH_5(0);
1077 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_4_5);
1078
1079 val = DSI_PKT_LEN_6_7_LENGTH_6(0) | DSI_PKT_LEN_6_7_LENGTH_7(0);
1080 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_6_7);
1081}
1082
1083static void tegra_dsi_setup_cmd_mode_pkt_length(struct tegra_dc *dc,
1084 struct tegra_dc_dsi_data *dsi)
1085{
1086 unsigned long val;
1087 unsigned long act_bytes;
1088
1089 act_bytes = dc->mode.h_active * dsi->pixel_scaler_mul /
1090 dsi->pixel_scaler_div + 1;
1091
1092 val = DSI_PKT_LEN_0_1_LENGTH_0(0) | DSI_PKT_LEN_0_1_LENGTH_1(0);
1093 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_0_1);
1094
1095 val = DSI_PKT_LEN_2_3_LENGTH_2(0) | DSI_PKT_LEN_2_3_LENGTH_3(act_bytes);
1096 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_2_3);
1097
1098 val = DSI_PKT_LEN_4_5_LENGTH_4(0) | DSI_PKT_LEN_4_5_LENGTH_5(act_bytes);
1099 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_4_5);
1100
1101 val = DSI_PKT_LEN_6_7_LENGTH_6(0) | DSI_PKT_LEN_6_7_LENGTH_7(0x0f0f);
1102 tegra_dsi_writel(dsi, val, DSI_PKT_LEN_6_7);
1103}
1104
1105static void tegra_dsi_set_pkt_length(struct tegra_dc *dc,
1106 struct tegra_dc_dsi_data *dsi)
1107{
1108 if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST)
1109 return;
1110
1111 if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_VIDEO_MODE)
1112 tegra_dsi_setup_video_mode_pkt_length(dc, dsi);
1113 else
1114 tegra_dsi_setup_cmd_mode_pkt_length(dc, dsi);
1115}
1116
1117static void tegra_dsi_set_pkt_seq(struct tegra_dc *dc,
1118 struct tegra_dc_dsi_data *dsi)
1119{
1120 const u32 *pkt_seq;
1121 u32 rgb_info;
1122 u32 pkt_seq_3_5_rgb_lo;
1123 u32 pkt_seq_3_5_rgb_hi;
1124 u32 val;
1125 u32 reg;
1126 u8 i;
1127
1128 if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST)
1129 return;
1130
1131 switch (dsi->info.pixel_format) {
1132 case TEGRA_DSI_PIXEL_FORMAT_16BIT_P:
1133 rgb_info = CMD_RGB_16BPP;
1134 break;
1135 case TEGRA_DSI_PIXEL_FORMAT_18BIT_P:
1136 rgb_info = CMD_RGB_18BPP;
1137 break;
1138 case TEGRA_DSI_PIXEL_FORMAT_18BIT_NP:
1139 rgb_info = CMD_RGB_18BPPNP;
1140 break;
1141 case TEGRA_DSI_PIXEL_FORMAT_24BIT_P:
1142 default:
1143 rgb_info = CMD_RGB_24BPP;
1144 break;
1145 }
1146
1147 pkt_seq_3_5_rgb_lo = 0;
1148 pkt_seq_3_5_rgb_hi = 0;
1149 if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE)
1150 pkt_seq = dsi_pkt_seq_cmd_mode;
1151 else {
1152 switch (dsi->info.video_burst_mode) {
1153 case TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED:
1154 case TEGRA_DSI_VIDEO_BURST_MODE_LOW_SPEED:
1155 case TEGRA_DSI_VIDEO_BURST_MODE_MEDIUM_SPEED:
1156 case TEGRA_DSI_VIDEO_BURST_MODE_FAST_SPEED:
1157 case TEGRA_DSI_VIDEO_BURST_MODE_FASTEST_SPEED:
1158 pkt_seq_3_5_rgb_lo =
1159 DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info);
1160 if (!dsi->info.no_pkt_seq_eot)
1161 pkt_seq = dsi_pkt_seq_video_burst;
1162 else
1163 pkt_seq = dsi_pkt_seq_video_burst_no_eot;
1164 break;
1165 case TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END:
1166 pkt_seq_3_5_rgb_hi =
1167 DSI_PKT_SEQ_3_HI_PKT_34_ID(rgb_info);
1168 pkt_seq = dsi_pkt_seq_video_non_burst_syne;
1169 break;
1170 case TEGRA_DSI_VIDEO_NONE_BURST_MODE:
1171 default:
1172 pkt_seq_3_5_rgb_lo =
1173 DSI_PKT_SEQ_3_LO_PKT_32_ID(rgb_info);
1174 pkt_seq = dsi_pkt_seq_video_non_burst;
1175 break;
1176 }
1177 }
1178
1179 for (i = 0; i < NUMOF_PKT_SEQ; i++) {
1180 val = pkt_seq[i];
1181 reg = dsi_pkt_seq_reg[i];
1182 if ((reg == DSI_PKT_SEQ_3_LO) || (reg == DSI_PKT_SEQ_5_LO))
1183 val |= pkt_seq_3_5_rgb_lo;
1184 if ((reg == DSI_PKT_SEQ_3_HI) || (reg == DSI_PKT_SEQ_5_HI))
1185 val |= pkt_seq_3_5_rgb_hi;
1186 tegra_dsi_writel(dsi, val, reg);
1187 }
1188}
1189
1190static void tegra_dsi_reset_underflow_overflow
1191 (struct tegra_dc_dsi_data *dsi)
1192{
1193 u32 val;
1194
1195 val = tegra_dsi_readl(dsi, DSI_STATUS);
1196 val &= (DSI_STATUS_LB_OVERFLOW(0x1) | DSI_STATUS_LB_UNDERFLOW(0x1));
1197 if (val) {
1198 if (val & DSI_STATUS_LB_OVERFLOW(0x1))
1199 dev_warn(&dsi->dc->ndev->dev,
1200 "dsi: video fifo overflow. Resetting flag\n");
1201 if (val & DSI_STATUS_LB_UNDERFLOW(0x1))
1202 dev_warn(&dsi->dc->ndev->dev,
1203 "dsi: video fifo underflow. Resetting flag\n");
1204 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
1205 val |= DSI_HOST_CONTROL_FIFO_STAT_RESET(0x1);
1206 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
1207 udelay(5);
1208 }
1209}
1210
1211static void tegra_dsi_stop_dc_stream(struct tegra_dc *dc,
1212 struct tegra_dc_dsi_data *dsi)
1213{
1214 tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND);
1215 tegra_dc_writel(dc, 0, DC_DISP_DISP_WIN_OPTIONS);
1216 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
1217 tegra_dc_writel(dc, GENERAL_ACT_REQ , DC_CMD_STATE_CONTROL);
1218
1219 dsi->status.dc_stream = DSI_DC_STREAM_DISABLE;
1220}
1221
1222static void tegra_dsi_stop_dc_stream_at_frame_end(struct tegra_dc *dc,
1223 struct tegra_dc_dsi_data *dsi)
1224{
1225 int val;
1226 long timeout;
1227 u32 frame_period = DIV_ROUND_UP(S_TO_MS(1), dsi->info.refresh_rate);
1228
1229 /* stop dc */
1230 tegra_dsi_stop_dc_stream(dc, dsi);
1231
1232 /* enable frame end interrupt */
1233 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
1234 val |= FRAME_END_INT;
1235 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
1236
1237 /* wait for frame_end completion.
1238 * timeout is 2 frame duration to accomodate for
1239 * internal delay.
1240 */
1241 timeout = wait_for_completion_interruptible_timeout(
1242 &dc->frame_end_complete,
1243 msecs_to_jiffies(2 * frame_period));
1244
1245 /* disable frame end interrupt */
1246 val = tegra_dc_readl(dc, DC_CMD_INT_MASK);
1247 val &= ~FRAME_END_INT;
1248 tegra_dc_writel(dc, val, DC_CMD_INT_MASK);
1249
1250 if (timeout == 0)
1251 dev_warn(&dc->ndev->dev,
1252 "DC doesn't stop at end of frame.\n");
1253
1254 tegra_dsi_reset_underflow_overflow(dsi);
1255}
1256
1257static void tegra_dsi_start_dc_stream(struct tegra_dc *dc,
1258 struct tegra_dc_dsi_data *dsi)
1259{
1260 u32 val;
1261
1262 tegra_dc_writel(dc, DSI_ENABLE, DC_DISP_DISP_WIN_OPTIONS);
1263
1264 /* TODO: clean up */
1265 tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
1266 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
1267 DC_CMD_DISPLAY_POWER_CONTROL);
1268
1269 /* Configure one-shot mode or continuous mode */
1270 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE) {
1271 /* disable LSPI/LCD_DE output */
1272 val = PIN_OUTPUT_LSPI_OUTPUT_DIS;
1273 tegra_dc_writel(dc, val, DC_COM_PIN_OUTPUT_ENABLE3);
1274
1275 /* enable MSF & set MSF polarity */
1276 val = MSF_ENABLE | MSF_LSPI;
1277 if (!dsi->info.te_polarity_low)
1278 val |= MSF_POLARITY_HIGH;
1279 else
1280 val |= MSF_POLARITY_LOW;
1281 tegra_dc_writel(dc, val, DC_CMD_DISPLAY_COMMAND_OPTION0);
1282
1283 /* set non-continuous mode */
1284 tegra_dc_writel(dc, DISP_CTRL_MODE_NC_DISPLAY,
1285 DC_CMD_DISPLAY_COMMAND);
1286 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
1287 tegra_dc_writel(dc, GENERAL_ACT_REQ | NC_HOST_TRIG,
1288 DC_CMD_STATE_CONTROL);
1289 } else {
1290 /* set continuous mode */
1291 tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY,
1292 DC_CMD_DISPLAY_COMMAND);
1293 tegra_dc_writel(dc, GENERAL_UPDATE, DC_CMD_STATE_CONTROL);
1294 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
1295 }
1296
1297 dsi->status.dc_stream = DSI_DC_STREAM_ENABLE;
1298}
1299
1300static void tegra_dsi_set_dc_clk(struct tegra_dc *dc,
1301 struct tegra_dc_dsi_data *dsi)
1302{
1303 u32 shift_clk_div_register;
1304 u32 val;
1305
1306 /* Get the corresponding register value of shift_clk_div. */
1307 shift_clk_div_register = dsi->shift_clk_div * 2 - 2;
1308
1309#ifndef CONFIG_TEGRA_SILICON_PLATFORM
1310 shift_clk_div_register = 1;
1311#endif
1312
1313 /* TODO: find out if PCD3 option is required */
1314 val = PIXEL_CLK_DIVIDER_PCD1 |
1315 SHIFT_CLK_DIVIDER(shift_clk_div_register);
1316 tegra_dc_writel(dc, val, DC_DISP_DISP_CLOCK_CONTROL);
1317}
1318
1319static void tegra_dsi_set_dsi_clk(struct tegra_dc *dc,
1320 struct tegra_dc_dsi_data *dsi, u32 clk)
1321{
1322 u32 rm;
1323
1324 /* Round up to MHz */
1325 rm = clk % 1000;
1326 if (rm != 0)
1327 clk -= rm;
1328
1329 /* Set up pixel clock */
1330 dc->shift_clk_div = dsi->shift_clk_div;
1331 dc->mode.pclk = (clk * 1000) / dsi->shift_clk_div;
1332 /* TODO: Define one shot work delay in board file. */
1333 /* Since for one-shot mode, refresh rate is usually set larger than
1334 * expected refresh rate, it needs at least 3 frame period. Less
1335 * delay one shot work is, more powering saving we have. */
1336 dc->one_shot_delay_ms = 4 *
1337 DIV_ROUND_UP(S_TO_MS(1), dsi->info.refresh_rate);
1338
1339 /* Enable DSI clock */
1340 tegra_dc_setup_clk(dc, dsi->dsi_clk);
1341 if (!dsi->clk_ref) {
1342 dsi->clk_ref = true;
1343 clk_enable(dsi->dsi_clk);
1344 tegra_periph_reset_deassert(dsi->dsi_clk);
1345 }
1346 dsi->current_dsi_clk_khz = clk_get_rate(dsi->dsi_clk) / 1000;
1347 dsi->current_bit_clk_ns = 1000*1000 / (dsi->current_dsi_clk_khz * 2);
1348}
1349
1350static void tegra_dsi_hs_clk_out_enable(struct tegra_dc_dsi_data *dsi)
1351{
1352 u32 val;
1353
1354 val = tegra_dsi_readl(dsi, DSI_CONTROL);
1355 val &= ~DSI_CONTROL_HS_CLK_CTRL(1);
1356
1357 if (dsi->info.video_clock_mode == TEGRA_DSI_VIDEO_CLOCK_CONTINUOUS) {
1358 val |= DSI_CONTROL_HS_CLK_CTRL(CONTINUOUS);
1359 dsi->status.clk_mode = DSI_PHYCLK_CONTINUOUS;
1360 } else {
1361 val |= DSI_CONTROL_HS_CLK_CTRL(TX_ONLY);
1362 dsi->status.clk_mode = DSI_PHYCLK_TX_ONLY;
1363 }
1364 tegra_dsi_writel(dsi, val, DSI_CONTROL);
1365
1366 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
1367 val &= ~DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(1);
1368 val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_HIGH);
1369 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
1370
1371 dsi->status.clk_out = DSI_PHYCLK_OUT_EN;
1372}
1373
1374static void tegra_dsi_hs_clk_out_enable_in_lp(struct tegra_dc_dsi_data *dsi)
1375{
1376 u32 val;
1377 tegra_dsi_hs_clk_out_enable(dsi);
1378
1379 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
1380 val &= ~DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(1);
1381 val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW);
1382 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
1383}
1384
1385static void tegra_dsi_hs_clk_out_disable(struct tegra_dc *dc,
1386 struct tegra_dc_dsi_data *dsi)
1387{
1388 u32 val;
1389
1390 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
1391 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
1392
1393 tegra_dsi_writel(dsi, TEGRA_DSI_DISABLE, DSI_POWER_CONTROL);
1394 /* stabilization delay */
1395 udelay(300);
1396
1397 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
1398 val &= ~DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(1);
1399 val |= DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW);
1400 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
1401
1402 tegra_dsi_writel(dsi, TEGRA_DSI_ENABLE, DSI_POWER_CONTROL);
1403 /* stabilization delay */
1404 udelay(300);
1405
1406 dsi->status.clk_mode = DSI_PHYCLK_NOT_INIT;
1407 dsi->status.clk_out = DSI_PHYCLK_OUT_DIS;
1408}
1409
1410static void tegra_dsi_set_control_reg_lp(struct tegra_dc_dsi_data *dsi)
1411{
1412 u32 dsi_control;
1413 u32 host_dsi_control;
1414 u32 max_threshold;
1415
1416 dsi_control = dsi->dsi_control_val | DSI_CTRL_HOST_DRIVEN;
1417 host_dsi_control = HOST_DSI_CTRL_COMMON |
1418 HOST_DSI_CTRL_HOST_DRIVEN |
1419 DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(TEGRA_DSI_LOW);
1420 max_threshold = DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_HOST_FIFO_DEPTH);
1421
1422 tegra_dsi_writel(dsi, max_threshold, DSI_MAX_THRESHOLD);
1423 tegra_dsi_writel(dsi, dsi_control, DSI_CONTROL);
1424 tegra_dsi_writel(dsi, host_dsi_control, DSI_HOST_DSI_CONTROL);
1425
1426 dsi->status.driven = DSI_DRIVEN_MODE_HOST;
1427 dsi->status.clk_burst = DSI_CLK_BURST_NOT_INIT;
1428 dsi->status.vtype = DSI_VIDEO_TYPE_NOT_INIT;
1429}
1430
1431static void tegra_dsi_set_control_reg_hs(struct tegra_dc_dsi_data *dsi)
1432{
1433 u32 dsi_control;
1434 u32 host_dsi_control;
1435 u32 max_threshold;
1436 u32 dcs_cmd;
1437
1438 dsi_control = dsi->dsi_control_val;
1439 host_dsi_control = HOST_DSI_CTRL_COMMON;
1440 max_threshold = 0;
1441 dcs_cmd = 0;
1442
1443 if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_HOST) {
1444 dsi_control |= DSI_CTRL_HOST_DRIVEN;
1445 host_dsi_control |= HOST_DSI_CTRL_HOST_DRIVEN;
1446 max_threshold =
1447 DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_HOST_FIFO_DEPTH);
1448 dsi->status.driven = DSI_DRIVEN_MODE_HOST;
1449 } else {
1450 dsi_control |= DSI_CTRL_DC_DRIVEN;
1451 host_dsi_control |= HOST_DSI_CTRL_DC_DRIVEN;
1452 max_threshold =
1453 DSI_MAX_THRESHOLD_MAX_THRESHOLD(DSI_VIDEO_FIFO_DEPTH);
1454 dsi->status.driven = DSI_DRIVEN_MODE_DC;
1455 }
1456
1457 if (dsi->info.video_data_type == TEGRA_DSI_VIDEO_TYPE_COMMAND_MODE) {
1458 dsi_control |= DSI_CTRL_CMD_MODE;
1459 dcs_cmd = DSI_DCS_CMDS_LT5_DCS_CMD(DSI_WRITE_MEMORY_START)|
1460 DSI_DCS_CMDS_LT3_DCS_CMD(DSI_WRITE_MEMORY_CONTINUE);
1461 dsi->status.vtype = DSI_VIDEO_TYPE_CMD_MODE;
1462
1463 } else {
1464 dsi_control |= DSI_CTRL_VIDEO_MODE;
1465 dsi->status.vtype = DSI_VIDEO_TYPE_VIDEO_MODE;
1466 }
1467
1468 tegra_dsi_writel(dsi, max_threshold, DSI_MAX_THRESHOLD);
1469 tegra_dsi_writel(dsi, dcs_cmd, DSI_DCS_CMDS);
1470 tegra_dsi_writel(dsi, dsi_control, DSI_CONTROL);
1471 tegra_dsi_writel(dsi, host_dsi_control, DSI_HOST_DSI_CONTROL);
1472}
1473
1474static void tegra_dsi_pad_calibration(struct tegra_dc_dsi_data *dsi)
1475{
1476 u32 val;
1477
1478 val = DSI_PAD_CONTROL_PAD_LPUPADJ(0x1) |
1479 DSI_PAD_CONTROL_PAD_LPDNADJ(0x1) |
1480 DSI_PAD_CONTROL_PAD_PREEMP_EN(0x1) |
1481 DSI_PAD_CONTROL_PAD_SLEWDNADJ(0x6) |
1482 DSI_PAD_CONTROL_PAD_SLEWUPADJ(0x6);
1483 if (!dsi->ulpm) {
1484 val |= DSI_PAD_CONTROL_PAD_PDIO(0) |
1485 DSI_PAD_CONTROL_PAD_PDIO_CLK(0) |
1486 DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_DISABLE);
1487 } else {
1488 val |= DSI_PAD_CONTROL_PAD_PDIO(0x3) |
1489 DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
1490 DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
1491 }
1492 tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
1493
1494 val = MIPI_CAL_TERMOSA(0x4);
1495 tegra_vi_csi_writel(val, CSI_CILA_MIPI_CAL_CONFIG_0);
1496
1497 val = MIPI_CAL_TERMOSB(0x4);
1498 tegra_vi_csi_writel(val, CSI_CILB_MIPI_CAL_CONFIG_0);
1499
1500 val = MIPI_CAL_HSPUOSD(0x3) | MIPI_CAL_HSPDOSD(0x4);
1501 tegra_vi_csi_writel(val, CSI_DSI_MIPI_CAL_CONFIG);
1502
1503 val = PAD_DRIV_DN_REF(0x5) | PAD_DRIV_UP_REF(0x7);
1504 tegra_vi_csi_writel(val, CSI_MIPIBIAS_PAD_CONFIG);
1505
1506 val = PAD_CIL_PDVREG(0x0);
1507 tegra_vi_csi_writel(val, CSI_CIL_PAD_CONFIG);
1508}
1509
1510static int tegra_dsi_init_hw(struct tegra_dc *dc,
1511 struct tegra_dc_dsi_data *dsi)
1512{
1513 u32 i;
1514
1515 tegra_dsi_writel(dsi,
1516 DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE),
1517 DSI_POWER_CONTROL);
1518 /* stabilization delay */
1519 udelay(300);
1520
1521 tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz);
1522 if (dsi->info.dsi_instance) {
1523 /* TODO:Set the misc register*/
1524 }
1525
1526 /* TODO: only need to change the timing for bta */
1527 tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_LP_MODE);
1528
1529 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
1530 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
1531
1532 /* Initializing DSI registers */
1533 for (i = 0; i < ARRAY_SIZE(init_reg); i++)
1534 tegra_dsi_writel(dsi, 0, init_reg[i]);
1535
1536 tegra_dsi_writel(dsi, dsi->dsi_control_val, DSI_CONTROL);
1537
1538 tegra_dsi_pad_calibration(dsi);
1539
1540 tegra_dsi_writel(dsi,
1541 DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE),
1542 DSI_POWER_CONTROL);
1543 /* stabilization delay */
1544 udelay(300);
1545
1546 dsi->status.init = DSI_MODULE_INIT;
1547 dsi->status.lphs = DSI_LPHS_NOT_INIT;
1548 dsi->status.vtype = DSI_VIDEO_TYPE_NOT_INIT;
1549 dsi->status.driven = DSI_DRIVEN_MODE_NOT_INIT;
1550 dsi->status.clk_out = DSI_PHYCLK_OUT_DIS;
1551 dsi->status.clk_mode = DSI_PHYCLK_NOT_INIT;
1552 dsi->status.clk_burst = DSI_CLK_BURST_NOT_INIT;
1553 dsi->status.dc_stream = DSI_DC_STREAM_DISABLE;
1554 dsi->status.lp_op = DSI_LP_OP_NOT_INIT;
1555
1556 return 0;
1557}
1558
1559static int tegra_dsi_set_to_lp_mode(struct tegra_dc *dc,
1560 struct tegra_dc_dsi_data *dsi, u8 lp_op)
1561{
1562 int err;
1563
1564 if (dsi->status.init != DSI_MODULE_INIT) {
1565 err = -EPERM;
1566 goto fail;
1567 }
1568
1569 if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE &&
1570 dsi->status.lp_op == lp_op)
1571 goto success;
1572
1573 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
1574 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
1575
1576 /* disable/enable hs clk according to enable_hs_clock_on_lp_cmd_mode */
1577 if ((dsi->status.clk_out == DSI_PHYCLK_OUT_EN) &&
1578 (!dsi->info.enable_hs_clock_on_lp_cmd_mode))
1579 tegra_dsi_hs_clk_out_disable(dc, dsi);
1580
1581 dsi->target_lp_clk_khz = tegra_dsi_get_lp_clk_rate(dsi, lp_op);
1582 if (dsi->current_dsi_clk_khz != dsi->target_lp_clk_khz) {
1583 tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_lp_clk_khz);
1584 tegra_dsi_set_timeout(dsi);
1585 }
1586
1587 tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_LP_MODE);
1588
1589 tegra_dsi_set_control_reg_lp(dsi);
1590
1591 if ((dsi->status.clk_out == DSI_PHYCLK_OUT_DIS) &&
1592 (dsi->info.enable_hs_clock_on_lp_cmd_mode))
1593 tegra_dsi_hs_clk_out_enable_in_lp(dsi);
1594
1595 dsi->status.lphs = DSI_LPHS_IN_LP_MODE;
1596 dsi->status.lp_op = lp_op;
1597success:
1598 err = 0;
1599fail:
1600 return err;
1601}
1602
1603static int tegra_dsi_set_to_hs_mode(struct tegra_dc *dc,
1604 struct tegra_dc_dsi_data *dsi)
1605{
1606 int err;
1607
1608 if (dsi->status.init != DSI_MODULE_INIT) {
1609 err = -EPERM;
1610 goto fail;
1611 }
1612
1613 if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE)
1614 goto success;
1615
1616 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
1617 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
1618
1619 if ((dsi->status.clk_out == DSI_PHYCLK_OUT_EN) &&
1620 (!dsi->info.enable_hs_clock_on_lp_cmd_mode))
1621 tegra_dsi_hs_clk_out_disable(dc, dsi);
1622
1623 if (dsi->current_dsi_clk_khz != dsi->target_hs_clk_khz) {
1624 tegra_dsi_set_dsi_clk(dc, dsi, dsi->target_hs_clk_khz);
1625 tegra_dsi_set_timeout(dsi);
1626 }
1627
1628 tegra_dsi_set_phy_timing(dsi, DSI_LPHS_IN_HS_MODE);
1629
1630 if (dsi->driven_mode == TEGRA_DSI_DRIVEN_BY_DC) {
1631 tegra_dsi_set_pkt_seq(dc, dsi);
1632 tegra_dsi_set_pkt_length(dc, dsi);
1633 tegra_dsi_set_sol_delay(dc, dsi);
1634 tegra_dsi_set_dc_clk(dc, dsi);
1635 }
1636
1637 tegra_dsi_set_control_reg_hs(dsi);
1638
1639 if (dsi->status.clk_out == DSI_PHYCLK_OUT_DIS ||
1640 dsi->info.enable_hs_clock_on_lp_cmd_mode)
1641 tegra_dsi_hs_clk_out_enable(dsi);
1642
1643 dsi->status.lphs = DSI_LPHS_IN_HS_MODE;
1644success:
1645 dsi->status.lp_op = DSI_LP_OP_NOT_INIT;
1646 err = 0;
1647fail:
1648 return err;
1649}
1650
1651static bool tegra_dsi_write_busy(struct tegra_dc_dsi_data *dsi)
1652{
1653 u32 timeout = 0;
1654 bool retVal = true;
1655
1656 while (timeout <= DSI_MAX_COMMAND_DELAY_USEC) {
1657 if (!(DSI_TRIGGER_HOST_TRIGGER(0x1) &
1658 tegra_dsi_readl(dsi, DSI_TRIGGER))) {
1659 retVal = false;
1660 break;
1661 }
1662 udelay(DSI_COMMAND_DELAY_STEPS_USEC);
1663 timeout += DSI_COMMAND_DELAY_STEPS_USEC;
1664 }
1665
1666 return retVal;
1667}
1668
1669static bool tegra_dsi_read_busy(struct tegra_dc_dsi_data *dsi)
1670{
1671 u32 timeout = 0;
1672 bool retVal = true;
1673
1674 while (timeout < DSI_STATUS_POLLING_DURATION_USEC) {
1675 if (!(DSI_HOST_DSI_CONTROL_IMM_BTA(0x1) &
1676 tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL))) {
1677 retVal = false;
1678 break;
1679 }
1680 udelay(DSI_STATUS_POLLING_DELAY_USEC);
1681 timeout += DSI_STATUS_POLLING_DELAY_USEC;
1682 }
1683
1684 return retVal;
1685}
1686
1687static bool tegra_dsi_host_busy(struct tegra_dc_dsi_data *dsi)
1688{
1689 int err = 0;
1690
1691 if (tegra_dsi_write_busy(dsi)) {
1692 err = -EBUSY;
1693 dev_err(&dsi->dc->ndev->dev,
1694 "DSI trigger bit already set\n");
1695 goto fail;
1696 }
1697
1698 if (tegra_dsi_read_busy(dsi)) {
1699 err = -EBUSY;
1700 dev_err(&dsi->dc->ndev->dev,
1701 "DSI immediate bta bit already set\n");
1702 goto fail;
1703 }
1704fail:
1705 return (err < 0 ? true : false);
1706}
1707
1708static void tegra_dsi_soft_reset(struct tegra_dc_dsi_data *dsi)
1709{
1710 u32 trigger;
1711 u32 status;
1712
1713 tegra_dsi_writel(dsi,
1714 DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE),
1715 DSI_POWER_CONTROL);
1716 /* stabilization delay */
1717 udelay(300);
1718
1719 tegra_dsi_writel(dsi,
1720 DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_ENABLE),
1721 DSI_POWER_CONTROL);
1722 /* stabilization delay */
1723 udelay(300);
1724
1725 /* dsi HW does not clear host trigger bit automatically
1726 * on dsi interface disable if host fifo is empty
1727 */
1728 trigger = tegra_dsi_readl(dsi, DSI_TRIGGER);
1729 status = tegra_dsi_readl(dsi, DSI_STATUS);
1730 if (trigger & DSI_TRIGGER_HOST_TRIGGER(0x1) &&
1731 status & DSI_STATUS_IDLE(0x1)) {
1732 trigger &= ~(DSI_TRIGGER_HOST_TRIGGER(0x1));
1733 tegra_dsi_writel(dsi, trigger, DSI_TRIGGER);
1734 }
1735}
1736
1737static void tegra_dsi_reset_read_count(struct tegra_dc_dsi_data *dsi)
1738{
1739 u32 val;
1740
1741 val = tegra_dsi_readl(dsi, DSI_STATUS);
1742 val &= DSI_STATUS_RD_FIFO_COUNT(0x1f);
1743 if (val) {
1744 dev_warn(&dsi->dc->ndev->dev,
1745 "DSI read count not zero, resetting\n");
1746 tegra_dsi_soft_reset(dsi);
1747 }
1748}
1749
1750static struct dsi_status *tegra_dsi_save_state_switch_to_host_cmd_mode(
1751 struct tegra_dc_dsi_data *dsi,
1752 struct tegra_dc *dc,
1753 u8 lp_op)
1754{
1755 struct dsi_status *init_status;
1756 int err;
1757
1758 init_status = kzalloc(sizeof(*init_status), GFP_KERNEL);
1759 if (!init_status)
1760 return ERR_PTR(-ENOMEM);
1761
1762 *init_status = dsi->status;
1763
1764 if (dsi->status.lphs == DSI_LPHS_IN_HS_MODE) {
1765 if (dsi->status.driven == DSI_DRIVEN_MODE_DC) {
1766 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
1767 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
1768 dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_HOST;
1769 if (dsi->info.hs_cmd_mode_supported) {
1770 err = tegra_dsi_set_to_hs_mode(dc, dsi);
1771 if (err < 0) {
1772 dev_err(&dc->ndev->dev,
1773 "Switch to HS host mode failed\n");
1774 goto fail;
1775 }
1776 }
1777 }
1778 if (!dsi->info.hs_cmd_mode_supported) {
1779 err =
1780 tegra_dsi_set_to_lp_mode(dc, dsi, lp_op);
1781 if (err < 0) {
1782 dev_err(&dc->ndev->dev,
1783 "DSI failed to go to LP mode\n");
1784 goto fail;
1785 }
1786 }
1787 } else if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE) {
1788 if (dsi->status.lp_op != lp_op) {
1789 err = tegra_dsi_set_to_lp_mode(dc, dsi, lp_op);
1790 if (err < 0) {
1791 dev_err(&dc->ndev->dev,
1792 "DSI failed to go to LP mode\n");
1793 goto fail;
1794 }
1795 }
1796 }
1797
1798 return init_status;
1799fail:
1800 kfree(init_status);
1801 return ERR_PTR(err);
1802}
1803
1804static struct dsi_status *tegra_dsi_prepare_host_transmission(
1805 struct tegra_dc *dc,
1806 struct tegra_dc_dsi_data *dsi,
1807 u8 lp_op)
1808{
1809 int err = 0;
1810 struct dsi_status *init_status;
1811
1812 if (dsi->status.init != DSI_MODULE_INIT ||
1813 dsi->ulpm) {
1814 err = -EPERM;
1815 goto fail;
1816 }
1817
1818 if (tegra_dsi_host_busy(dsi)) {
1819 tegra_dsi_soft_reset(dsi);
1820 if (tegra_dsi_host_busy(dsi)) {
1821 err = -EBUSY;
1822 dev_err(&dc->ndev->dev, "DSI host busy\n");
1823 goto fail;
1824 }
1825 }
1826
1827 if (lp_op == DSI_LP_OP_READ)
1828 tegra_dsi_reset_read_count(dsi);
1829
1830 if (dsi->status.lphs == DSI_LPHS_NOT_INIT) {
1831 err = tegra_dsi_set_to_lp_mode(dc, dsi, lp_op);
1832 if (err < 0) {
1833 dev_err(&dc->ndev->dev, "Failed to config LP write\n");
1834 goto fail;
1835 }
1836 }
1837
1838 init_status = tegra_dsi_save_state_switch_to_host_cmd_mode
1839 (dsi, dc, lp_op);
1840 if (IS_ERR_OR_NULL(init_status)) {
1841 err = PTR_ERR(init_status);
1842 dev_err(&dc->ndev->dev, "DSI state saving failed\n");
1843 goto fail;
1844 }
1845
1846 return init_status;
1847fail:
1848 return ERR_PTR(err);
1849}
1850
1851static int tegra_dsi_restore_state(struct tegra_dc *dc,
1852 struct tegra_dc_dsi_data *dsi,
1853 struct dsi_status *init_status)
1854{
1855 bool switch_back_to_dc_mode = false;
1856 bool switch_back_to_hs_mode = false;
1857 bool restart_dc_stream;
1858 int err = 0;
1859
1860 switch_back_to_dc_mode = (dsi->status.driven ==
1861 DSI_DRIVEN_MODE_HOST &&
1862 init_status->driven ==
1863 DSI_DRIVEN_MODE_DC);
1864 switch_back_to_hs_mode = (dsi->status.lphs ==
1865 DSI_LPHS_IN_LP_MODE &&
1866 init_status->lphs ==
1867 DSI_LPHS_IN_HS_MODE);
1868 restart_dc_stream = (dsi->status.dc_stream ==
1869 DSI_DC_STREAM_DISABLE &&
1870 init_status->dc_stream ==
1871 DSI_DC_STREAM_ENABLE);
1872
1873 if (dsi->status.lphs == DSI_LPHS_IN_LP_MODE &&
1874 init_status->lphs == DSI_LPHS_IN_LP_MODE) {
1875 if (dsi->status.lp_op != init_status->lp_op) {
1876 err =
1877 tegra_dsi_set_to_lp_mode(dc, dsi, init_status->lp_op);
1878 if (err < 0) {
1879 dev_err(&dc->ndev->dev,
1880 "Failed to config LP mode\n");
1881 goto fail;
1882 }
1883 }
1884 goto success;
1885 }
1886
1887 if (switch_back_to_dc_mode)
1888 dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC;
1889 if (switch_back_to_dc_mode || switch_back_to_hs_mode) {
1890 err = tegra_dsi_set_to_hs_mode(dc, dsi);
1891 if (err < 0) {
1892 dev_err(&dc->ndev->dev, "Failed to config HS mode\n");
1893 goto fail;
1894 }
1895 }
1896 if (restart_dc_stream)
1897 tegra_dsi_start_dc_stream(dc, dsi);
1898
1899success:
1900fail:
1901 kfree(init_status);
1902 return err;
1903}
1904
1905static int tegra_dsi_host_trigger(struct tegra_dc_dsi_data *dsi)
1906{
1907 int status = 0;
1908
1909 if (tegra_dsi_readl(dsi, DSI_TRIGGER)) {
1910 status = -EBUSY;
1911 goto fail;
1912 }
1913
1914 tegra_dsi_writel(dsi,
1915 DSI_TRIGGER_HOST_TRIGGER(TEGRA_DSI_ENABLE), DSI_TRIGGER);
1916
1917#if DSI_USE_SYNC_POINTS
1918 status = tegra_dsi_syncpt(dsi);
1919 if (status < 0) {
1920 dev_err(&dsi->dc->ndev->dev,
1921 "DSI syncpt for host trigger failed\n");
1922 goto fail;
1923 }
1924#else
1925 if (tegra_dsi_write_busy(dsi)) {
1926 status = -EBUSY;
1927 dev_err(&dsi->dc->ndev->dev,
1928 "Timeout waiting on write completion\n");
1929 }
1930#endif
1931
1932fail:
1933 return status;
1934}
1935
1936static int _tegra_dsi_write_data(struct tegra_dc_dsi_data *dsi,
1937 u8 *pdata, u8 data_id, u16 data_len)
1938{
1939 u8 virtual_channel;
1940 u8 *pval;
1941 u32 val;
1942 int err;
1943
1944 err = 0;
1945
1946 virtual_channel = dsi->info.virtual_channel <<
1947 DSI_VIR_CHANNEL_BIT_POSITION;
1948
1949 /* always use hw for ecc */
1950 val = (virtual_channel | data_id) << 0 |
1951 data_len << 8;
1952 tegra_dsi_writel(dsi, val, DSI_WR_DATA);
1953
1954 /* if pdata != NULL, pkt type is long pkt */
1955 if (pdata != NULL) {
1956 while (data_len) {
1957 if (data_len >= 4) {
1958 val = ((u32 *) pdata)[0];
1959 data_len -= 4;
1960 pdata += 4;
1961 } else {
1962 val = 0;
1963 pval = (u8 *) &val;
1964 do
1965 *pval++ = *pdata++;
1966 while (--data_len);
1967 }
1968 tegra_dsi_writel(dsi, val, DSI_WR_DATA);
1969 }
1970 }
1971
1972 err = tegra_dsi_host_trigger(dsi);
1973 if (err < 0)
1974 dev_err(&dsi->dc->ndev->dev, "DSI host trigger failed\n");
1975
1976 return err;
1977}
1978
1979int tegra_dsi_write_data(struct tegra_dc *dc,
1980 struct tegra_dc_dsi_data *dsi,
1981 u8 *pdata, u8 data_id, u16 data_len)
1982{
1983 int err = 0;
1984 struct dsi_status *init_status;
1985
1986 tegra_dc_io_start(dc);
1987
1988 init_status = tegra_dsi_prepare_host_transmission(
1989 dc, dsi, DSI_LP_OP_WRITE);
1990 if (IS_ERR_OR_NULL(init_status)) {
1991 err = PTR_ERR(init_status);
1992 dev_err(&dc->ndev->dev, "DSI host config failed\n");
1993 goto fail;
1994 }
1995
1996 err = _tegra_dsi_write_data(dsi, pdata, data_id, data_len);
1997fail:
1998 err = tegra_dsi_restore_state(dc, dsi, init_status);
1999 if (err < 0)
2000 dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
2001 tegra_dc_io_end(dc);
2002 return err;
2003}
2004EXPORT_SYMBOL(tegra_dsi_write_data);
2005
2006static int tegra_dsi_send_panel_cmd(struct tegra_dc *dc,
2007 struct tegra_dc_dsi_data *dsi,
2008 struct tegra_dsi_cmd *cmd,
2009 u32 n_cmd)
2010{
2011 u32 i;
2012 int err;
2013
2014 err = 0;
2015 for (i = 0; i < n_cmd; i++) {
2016 struct tegra_dsi_cmd *cur_cmd;
2017 cur_cmd = &cmd[i];
2018
2019 if (cur_cmd->cmd_type == TEGRA_DSI_DELAY_MS)
2020 mdelay(cur_cmd->sp_len_dly.delay_ms);
2021 else {
2022 err = tegra_dsi_write_data(dc, dsi,
2023 cur_cmd->pdata,
2024 cur_cmd->data_id,
2025 cur_cmd->sp_len_dly.data_len);
2026 if (err < 0)
2027 break;
2028 }
2029 }
2030 return err;
2031}
2032
2033static u8 get_8bit_ecc(u32 header)
2034{
2035 char ecc_parity[24] = {
2036 0x07, 0x0b, 0x0d, 0x0e, 0x13, 0x15, 0x16, 0x19,
2037 0x1a, 0x1c, 0x23, 0x25, 0x26, 0x29, 0x2a, 0x2c,
2038 0x31, 0x32, 0x34, 0x38, 0x1f, 0x2f, 0x37, 0x3b
2039 };
2040 u8 ecc_byte;
2041 int i;
2042
2043 ecc_byte = 0;
2044 for (i = 0; i < 24; i++)
2045 ecc_byte ^= ((header >> i) & 1) ? ecc_parity[i] : 0x00;
2046
2047 return ecc_byte;
2048}
2049
2050/* This function is written to send DCS short write (1 parameter) only.
2051 * This means the cmd will contain only 1 byte of index and 1 byte of value.
2052 * The data type ID is fixed at 0x15 and the ECC is calculated based on the
2053 * data in pdata.
2054 * The command will be sent by hardware every frame.
2055 * pdata should contain both the index + value for each cmd.
2056 * data_len will be the total number of bytes in pdata.
2057 */
2058int tegra_dsi_send_panel_short_cmd(struct tegra_dc *dc, u8 *pdata, u8 data_len)
2059{
2060 u8 ecc8bits = 0, data_len_orig = 0;
2061 u32 val = 0, pkthdr = 0;
2062 int err = 0, count = 0;
2063 struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
2064
2065 data_len_orig = data_len;
2066 if (pdata != NULL) {
2067 while (data_len) {
2068 if (data_len >= 2) {
2069 pkthdr = (CMD_SHORTW |
2070 (((u16 *)pdata)[0]) << 8 | 0x00 << 24);
2071 ecc8bits = get_8bit_ecc(pkthdr);
2072 val = (pkthdr | (ecc8bits << 24));
2073 data_len -= 2;
2074 pdata += 2;
2075 count++;
2076 }
2077 switch (count) {
2078 case 1:
2079 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_0);
2080 break;
2081 case 2:
2082 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_1);
2083 break;
2084 case 3:
2085 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_2);
2086 break;
2087 case 4:
2088 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_3);
2089 break;
2090 case 5:
2091 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_4);
2092 break;
2093 case 6:
2094 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_5);
2095 break;
2096 case 7:
2097 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_6);
2098 break;
2099 case 8:
2100 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_DATA_7);
2101 break;
2102 default:
2103 err = 1;
2104 break;
2105 }
2106 }
2107 }
2108
2109 val = DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(data_len_orig * 2)
2110 | DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(1);
2111 tegra_dsi_writel(dsi, val, DSI_INIT_SEQ_CONTROL);
2112
2113 return err;
2114}
2115EXPORT_SYMBOL(tegra_dsi_send_panel_short_cmd);
2116
2117static int tegra_dsi_bta(struct tegra_dc_dsi_data *dsi)
2118{
2119 u32 val;
2120 u32 poll_time;
2121 int err;
2122
2123 poll_time = 0;
2124 err = 0;
2125
2126 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
2127 val |= DSI_HOST_DSI_CONTROL_IMM_BTA(TEGRA_DSI_ENABLE);
2128 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
2129
2130#if DSI_USE_SYNC_POINTS
2131 /* FIXME: Workaround for nvhost_syncpt_read */
2132 dsi->syncpt_val = nvhost_syncpt_update_min(
2133 &nvhost_get_host(dsi->dc->ndev)->syncpt,
2134 dsi->syncpt_id);
2135
2136 val = DSI_INCR_SYNCPT_COND(OP_DONE) |
2137 DSI_INCR_SYNCPT_INDX(dsi->syncpt_id);
2138 tegra_dsi_writel(dsi, val, DSI_INCR_SYNCPT);
2139
2140 /* TODO: Use interrupt rather than polling */
2141 err = nvhost_syncpt_wait(&nvhost_get_host(dsi->dc->ndev)->syncpt,
2142 dsi->syncpt_id, dsi->syncpt_val + 1);
2143 if (err < 0)
2144 dev_err(&dsi->dc->ndev->dev,
2145 "DSI sync point failure\n");
2146 else
2147 (dsi->syncpt_val)++;
2148#else
2149 if (tegra_dsi_read_busy(dsi)) {
2150 err = -EBUSY;
2151 dev_err(&dsi->dc->ndev->dev,
2152 "Timeout wating on read completion\n");
2153 }
2154#endif
2155
2156 return err;
2157}
2158
2159static int tegra_dsi_parse_read_response(struct tegra_dc *dc,
2160 u32 rd_fifo_cnt, u8 *read_fifo)
2161{
2162 int err;
2163 u32 payload_size;
2164
2165 payload_size = 0;
2166 err = 0;
2167
2168 switch (read_fifo[0]) {
2169 case DSI_ESCAPE_CMD:
2170 dev_info(&dc->ndev->dev, "escape cmd[0x%x]\n", read_fifo[0]);
2171 break;
2172 case DSI_ACK_NO_ERR:
2173 dev_info(&dc->ndev->dev,
2174 "Panel ack, no err[0x%x]\n", read_fifo[0]);
2175 return err;
2176 default:
2177 dev_info(&dc->ndev->dev, "Invalid read response\n");
2178 break;
2179 }
2180
2181 switch (read_fifo[4] & 0xff) {
2182 case GEN_LONG_RD_RES:
2183 /* Fall through */
2184 case DCS_LONG_RD_RES:
2185 payload_size = (read_fifo[5] |
2186 (read_fifo[6] << 8)) & 0xFFFF;
2187 dev_info(&dc->ndev->dev, "Long read response Packet\n"
2188 "payload_size[0x%x]\n", payload_size);
2189 break;
2190 case GEN_1_BYTE_SHORT_RD_RES:
2191 /* Fall through */
2192 case DCS_1_BYTE_SHORT_RD_RES:
2193 payload_size = 1;
2194 dev_info(&dc->ndev->dev, "Short read response Packet\n"
2195 "payload_size[0x%x]\n", payload_size);
2196 break;
2197 case GEN_2_BYTE_SHORT_RD_RES:
2198 /* Fall through */
2199 case DCS_2_BYTE_SHORT_RD_RES:
2200 payload_size = 2;
2201 dev_info(&dc->ndev->dev, "Short read response Packet\n"
2202 "payload_size[0x%x]\n", payload_size);
2203 break;
2204 case ACK_ERR_RES:
2205 payload_size = 2;
2206 dev_info(&dc->ndev->dev, "Acknowledge error report response\n"
2207 "Packet payload_size[0x%x]\n", payload_size);
2208 break;
2209 default:
2210 dev_info(&dc->ndev->dev, "Invalid response packet\n");
2211 err = -EINVAL;
2212 break;
2213 }
2214 return err;
2215}
2216
2217static int tegra_dsi_read_fifo(struct tegra_dc *dc,
2218 struct tegra_dc_dsi_data *dsi,
2219 u8 *read_fifo)
2220{
2221 u32 val;
2222 u32 i;
2223 u32 poll_time = 0;
2224 u32 rd_fifo_cnt;
2225 int err = 0;
2226 u8 *read_fifo_cp = read_fifo;
2227
2228 while (poll_time < DSI_DELAY_FOR_READ_FIFO) {
2229 mdelay(1);
2230 val = tegra_dsi_readl(dsi, DSI_STATUS);
2231 rd_fifo_cnt = val & DSI_STATUS_RD_FIFO_COUNT(0x1f);
2232 if (rd_fifo_cnt << 2 > DSI_READ_FIFO_DEPTH)
2233 dev_err(&dc->ndev->dev,
2234 "DSI RD_FIFO_CNT is greater than RD_FIFO_DEPTH\n");
2235 break;
2236 poll_time++;
2237 }
2238
2239 if (rd_fifo_cnt == 0) {
2240 dev_info(&dc->ndev->dev,
2241 "DSI RD_FIFO_CNT is zero\n");
2242 err = -EINVAL;
2243 goto fail;
2244 }
2245
2246 if (val & (DSI_STATUS_LB_UNDERFLOW(0x1) |
2247 DSI_STATUS_LB_OVERFLOW(0x1))) {
2248 dev_warn(&dc->ndev->dev,
2249 "DSI overflow/underflow error\n");
2250 }
2251
2252 /* Read data from FIFO */
2253 for (i = 0; i < rd_fifo_cnt; i++) {
2254 val = tegra_dsi_readl(dsi, DSI_RD_DATA);
2255 if (enable_read_debug)
2256 dev_info(&dc->ndev->dev,
2257 "Read data[%d]: 0x%x\n", i, val);
2258 memcpy(read_fifo, &val, 4);
2259 read_fifo += 4;
2260 }
2261
2262 /* Make sure all the data is read from the FIFO */
2263 val = tegra_dsi_readl(dsi, DSI_STATUS);
2264 val &= DSI_STATUS_RD_FIFO_COUNT(0x1f);
2265 if (val)
2266 dev_err(&dc->ndev->dev, "DSI FIFO_RD_CNT not zero"
2267 " even after reading FIFO_RD_CNT words from read fifo\n");
2268
2269 if (enable_read_debug) {
2270 err =
2271 tegra_dsi_parse_read_response(dc, rd_fifo_cnt, read_fifo_cp);
2272 if (err < 0)
2273 dev_warn(&dc->ndev->dev, "Unexpected read data\n");
2274 }
2275fail:
2276 return err;
2277}
2278
2279int tegra_dsi_read_data(struct tegra_dc *dc,
2280 struct tegra_dc_dsi_data *dsi,
2281 u32 max_ret_payload_size,
2282 u32 panel_reg_addr, u8 *read_data)
2283{
2284 int err = 0;
2285 struct dsi_status *init_status;
2286
2287 tegra_dc_io_start(dc);
2288
2289 init_status = tegra_dsi_prepare_host_transmission(
2290 dc, dsi, DSI_LP_OP_WRITE);
2291 if (IS_ERR_OR_NULL(init_status)) {
2292 err = PTR_ERR(init_status);
2293 dev_err(&dc->ndev->dev, "DSI host config failed\n");
2294 goto fail;
2295 }
2296
2297 /* Set max return payload size in words */
2298 err = _tegra_dsi_write_data(dsi, NULL,
2299 dsi_command_max_return_pkt_size,
2300 max_ret_payload_size);
2301 if (err < 0) {
2302 dev_err(&dc->ndev->dev,
2303 "DSI write failed\n");
2304 goto fail;
2305 }
2306
2307 /* DCS to read given panel register */
2308 err = _tegra_dsi_write_data(dsi, NULL,
2309 dsi_command_dcs_read_with_no_params,
2310 panel_reg_addr);
2311 if (err < 0) {
2312 dev_err(&dc->ndev->dev,
2313 "DSI write failed\n");
2314 goto fail;
2315 }
2316
2317 tegra_dsi_reset_read_count(dsi);
2318
2319 if (dsi->status.lp_op == DSI_LP_OP_WRITE) {
2320 err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_READ);
2321 if (err < 0) {
2322 dev_err(&dc->ndev->dev,
2323 "DSI failed to go to LP read mode\n");
2324 goto fail;
2325 }
2326 }
2327
2328 err = tegra_dsi_bta(dsi);
2329 if (err < 0) {
2330 dev_err(&dc->ndev->dev,
2331 "DSI IMM BTA timeout\n");
2332 goto fail;
2333 }
2334
2335 err = tegra_dsi_read_fifo(dc, dsi, read_data);
2336 if (err < 0) {
2337 dev_err(&dc->ndev->dev, "DSI read fifo failure\n");
2338 goto fail;
2339 }
2340fail:
2341 err = tegra_dsi_restore_state(dc, dsi, init_status);
2342 if (err < 0)
2343 dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
2344 tegra_dc_io_end(dc);
2345 return err;
2346}
2347EXPORT_SYMBOL(tegra_dsi_read_data);
2348
2349int tegra_dsi_panel_sanity_check(struct tegra_dc *dc,
2350 struct tegra_dc_dsi_data *dsi)
2351{
2352 int err = 0;
2353 u8 read_fifo[DSI_READ_FIFO_DEPTH];
2354 struct dsi_status *init_status;
2355 static struct tegra_dsi_cmd dsi_nop_cmd =
2356 DSI_CMD_SHORT(0x05, 0x0, 0x0);
2357
2358 tegra_dc_io_start(dc);
2359
2360 init_status = tegra_dsi_prepare_host_transmission(
2361 dc, dsi, DSI_LP_OP_WRITE);
2362 if (IS_ERR_OR_NULL(init_status)) {
2363 err = PTR_ERR(init_status);
2364 dev_err(&dc->ndev->dev, "DSI host config failed\n");
2365 goto fail;
2366 }
2367
2368 err = _tegra_dsi_write_data(dsi, NULL, dsi_nop_cmd.data_id, 0x0);
2369 if (err < 0) {
2370 dev_err(&dc->ndev->dev, "DSI nop write failed\n");
2371 goto fail;
2372 }
2373
2374 tegra_dsi_reset_read_count(dsi);
2375
2376 if (dsi->status.lp_op == DSI_LP_OP_WRITE) {
2377 err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_READ);
2378 if (err < 0) {
2379 dev_err(&dc->ndev->dev,
2380 "DSI failed to go to LP read mode\n");
2381 goto fail;
2382 }
2383 }
2384
2385 err = tegra_dsi_bta(dsi);
2386 if (err < 0) {
2387 dev_err(&dc->ndev->dev, "DSI BTA failed\n");
2388 goto fail;
2389 }
2390
2391 err = tegra_dsi_read_fifo(dc, dsi, read_fifo);
2392 if (err < 0) {
2393 dev_err(&dc->ndev->dev, "DSI read fifo failure\n");
2394 goto fail;
2395 }
2396
2397 if (read_fifo[0] != DSI_ACK_NO_ERR) {
2398 dev_warn(&dc->ndev->dev,
2399 "Ack no error trigger message not received\n");
2400 err = -EAGAIN;
2401 }
2402fail:
2403 err = tegra_dsi_restore_state(dc, dsi, init_status);
2404 if (err < 0)
2405 dev_err(&dc->ndev->dev, "Failed to restore prev state\n");
2406 tegra_dc_io_end(dc);
2407 return err;
2408}
2409EXPORT_SYMBOL(tegra_dsi_panel_sanity_check);
2410
2411static int tegra_dsi_enter_ulpm(struct tegra_dc_dsi_data *dsi)
2412{
2413 u32 val;
2414 int ret;
2415
2416 ret = 0;
2417
2418 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
2419 val &= ~DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(3);
2420 val |= DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(ENTER_ULPM);
2421 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
2422
2423#if DSI_USE_SYNC_POINTS
2424 ret = tegra_dsi_syncpt(dsi);
2425 if (ret < 0) {
2426 dev_err(&dsi->dc->ndev->dev,
2427 "DSI syncpt for ulpm enter failed\n");
2428 goto fail;
2429 }
2430#else
2431 /* TODO: Find exact delay required */
2432 mdelay(10);
2433#endif
2434 dsi->ulpm = true;
2435fail:
2436 return ret;
2437}
2438
2439static int tegra_dsi_exit_ulpm(struct tegra_dc_dsi_data *dsi)
2440{
2441 u32 val;
2442 int ret;
2443
2444 ret = 0;
2445
2446 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
2447 val &= ~DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(3);
2448 val |= DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(EXIT_ULPM);
2449 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
2450
2451#if DSI_USE_SYNC_POINTS
2452 ret = tegra_dsi_syncpt(dsi);
2453 if (ret < 0) {
2454 dev_err(&dsi->dc->ndev->dev,
2455 "DSI syncpt for ulpm exit failed\n");
2456 goto fail;
2457 }
2458#else
2459 /* TODO: Find exact delay required */
2460 mdelay(10);
2461#endif
2462 dsi->ulpm = false;
2463
2464 val = tegra_dsi_readl(dsi, DSI_HOST_DSI_CONTROL);
2465 val &= ~DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(0x3);
2466 val |= DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(NORMAL);
2467 tegra_dsi_writel(dsi, val, DSI_HOST_DSI_CONTROL);
2468fail:
2469 return ret;
2470
2471}
2472
2473static void tegra_dc_dsi_enable(struct tegra_dc *dc)
2474{
2475 struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
2476 int err;
2477 u32 val;
2478
2479 tegra_dc_io_start(dc);
2480 mutex_lock(&dsi->lock);
2481
2482 /* Stop DC stream before configuring DSI registers
2483 * to avoid visible glitches on panel during transition
2484 * from bootloader to kernel driver
2485 */
2486 tegra_dsi_stop_dc_stream(dc, dsi);
2487
2488 if (dsi->enabled) {
2489 if (dsi->ulpm) {
2490 if (tegra_dsi_exit_ulpm(dsi) < 0) {
2491 dev_err(&dc->ndev->dev,
2492 "DSI failed to exit ulpm\n");
2493 goto fail;
2494 }
2495 }
2496
2497 if (dsi->info.panel_reset) {
2498 err = tegra_dsi_send_panel_cmd(dc, dsi,
2499 dsi->info.dsi_init_cmd,
2500 dsi->info.n_init_cmd);
2501 if (err < 0) {
2502 dev_err(&dc->ndev->dev,
2503 "dsi: error sending dsi init cmd\n");
2504 goto fail;
2505 }
2506 } else if (dsi->info.dsi_late_resume_cmd) {
2507 err = tegra_dsi_send_panel_cmd(dc, dsi,
2508 dsi->info.dsi_late_resume_cmd,
2509 dsi->info.n_late_resume_cmd);
2510 if (err < 0) {
2511 dev_err(&dc->ndev->dev,
2512 "dsi: error sending late resume cmd\n");
2513 goto fail;
2514 }
2515 }
2516 } else {
2517 err = tegra_dsi_init_hw(dc, dsi);
2518 if (err < 0) {
2519 dev_err(&dc->ndev->dev,
2520 "dsi: not able to init dsi hardware\n");
2521 goto fail;
2522 }
2523
2524 if (dsi->ulpm) {
2525 if (tegra_dsi_enter_ulpm(dsi) < 0) {
2526 dev_err(&dc->ndev->dev,
2527 "DSI failed to enter ulpm\n");
2528 goto fail;
2529 }
2530
2531 val = tegra_dsi_readl(dsi, DSI_PAD_CONTROL);
2532
2533 /* erase bits we're about to set */
2534 val &= ~(DSI_PAD_CONTROL_PAD_PDIO(0x3) |
2535 DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
2536 DSI_PAD_CONTROL_PAD_PULLDN_ENAB(0x1));
2537
2538 val |= (DSI_PAD_CONTROL_PAD_PDIO(0) |
2539 DSI_PAD_CONTROL_PAD_PDIO_CLK(0) |
2540 DSI_PAD_CONTROL_PAD_PULLDN_ENAB
2541 (TEGRA_DSI_DISABLE));
2542
2543 tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
2544 if (tegra_dsi_exit_ulpm(dsi) < 0) {
2545 dev_err(&dc->ndev->dev,
2546 "DSI failed to exit ulpm\n");
2547 goto fail;
2548 }
2549 }
2550
2551 err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
2552 if (err < 0) {
2553 dev_err(&dc->ndev->dev,
2554 "dsi: not able to set to lp mode\n");
2555 goto fail;
2556 }
2557
2558 err = tegra_dsi_send_panel_cmd(dc, dsi, dsi->info.dsi_init_cmd,
2559 dsi->info.n_init_cmd);
2560 if (err < 0) {
2561 dev_err(&dc->ndev->dev,
2562 "dsi: error while sending dsi init cmd\n");
2563 goto fail;
2564 }
2565
2566 err = tegra_dsi_set_to_hs_mode(dc, dsi);
2567 if (err < 0) {
2568 dev_err(&dc->ndev->dev,
2569 "dsi: not able to set to hs mode\n");
2570 goto fail;
2571 }
2572
2573 dsi->enabled = true;
2574 }
2575
2576 if (dsi->status.driven == DSI_DRIVEN_MODE_DC)
2577 tegra_dsi_start_dc_stream(dc, dsi);
2578fail:
2579 mutex_unlock(&dsi->lock);
2580 tegra_dc_io_end(dc);
2581}
2582
2583static void _tegra_dc_dsi_init(struct tegra_dc *dc)
2584{
2585 struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
2586
2587 tegra_dsi_init_sw(dc, dsi);
2588 /* TODO: Configure the CSI pad configuration */
2589}
2590
2591static int tegra_dc_dsi_cp_p_cmd(struct tegra_dsi_cmd *src,
2592 struct tegra_dsi_cmd *dst, u16 n_cmd)
2593{
2594 u16 i;
2595 u16 len;
2596
2597 memcpy(dst, src, sizeof(*dst) * n_cmd);
2598
2599 for (i = 0; i < n_cmd; i++)
2600 if (src[i].pdata) {
2601 len = sizeof(*src[i].pdata) *
2602 src[i].sp_len_dly.data_len;
2603 dst[i].pdata = kzalloc(len, GFP_KERNEL);
2604 if (!dst[i].pdata)
2605 goto free_cmd_pdata;
2606 memcpy(dst[i].pdata, src[i].pdata, len);
2607 }
2608
2609 return 0;
2610
2611free_cmd_pdata:
2612 for (--i; i >= 0; i--)
2613 if (dst[i].pdata)
2614 kfree(dst[i].pdata);
2615 return -ENOMEM;
2616}
2617
2618static int tegra_dc_dsi_cp_info(struct tegra_dc_dsi_data *dsi,
2619 struct tegra_dsi_out *p_dsi)
2620{
2621 struct tegra_dsi_cmd *p_init_cmd;
2622 struct tegra_dsi_cmd *p_early_suspend_cmd;
2623 struct tegra_dsi_cmd *p_late_resume_cmd;
2624 struct tegra_dsi_cmd *p_suspend_cmd;
2625 int err;
2626
2627 if (p_dsi->n_data_lanes > MAX_DSI_DATA_LANES)
2628 return -EINVAL;
2629
2630 p_init_cmd = kzalloc(sizeof(*p_init_cmd) *
2631 p_dsi->n_init_cmd, GFP_KERNEL);
2632 if (!p_init_cmd)
2633 return -ENOMEM;
2634
2635 if (p_dsi->dsi_early_suspend_cmd) {
2636 p_early_suspend_cmd = kzalloc(sizeof(*p_early_suspend_cmd) *
2637 p_dsi->n_early_suspend_cmd,
2638 GFP_KERNEL);
2639 if (!p_early_suspend_cmd) {
2640 err = -ENOMEM;
2641 goto err_free_init_cmd;
2642 }
2643 }
2644
2645 if (p_dsi->dsi_late_resume_cmd) {
2646 p_late_resume_cmd = kzalloc(sizeof(*p_late_resume_cmd) *
2647 p_dsi->n_late_resume_cmd,
2648 GFP_KERNEL);
2649 if (!p_late_resume_cmd) {
2650 err = -ENOMEM;
2651 goto err_free_p_early_suspend_cmd;
2652 }
2653 }
2654
2655 p_suspend_cmd = kzalloc(sizeof(*p_suspend_cmd) * p_dsi->n_suspend_cmd,
2656 GFP_KERNEL);
2657 if (!p_suspend_cmd) {
2658 err = -ENOMEM;
2659 goto err_free_p_late_resume_cmd;
2660 }
2661
2662 memcpy(&dsi->info, p_dsi, sizeof(dsi->info));
2663
2664 /* Copy panel init cmd */
2665 err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_init_cmd,
2666 p_init_cmd, p_dsi->n_init_cmd);
2667 if (err < 0)
2668 goto err_free;
2669 dsi->info.dsi_init_cmd = p_init_cmd;
2670
2671 /* Copy panel early suspend cmd */
2672 if (p_dsi->dsi_early_suspend_cmd) {
2673 err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_early_suspend_cmd,
2674 p_early_suspend_cmd,
2675 p_dsi->n_early_suspend_cmd);
2676 if (err < 0)
2677 goto err_free;
2678 dsi->info.dsi_early_suspend_cmd = p_early_suspend_cmd;
2679 }
2680
2681 /* Copy panel late resume cmd */
2682 if (p_dsi->dsi_late_resume_cmd) {
2683 err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_late_resume_cmd,
2684 p_late_resume_cmd,
2685 p_dsi->n_late_resume_cmd);
2686 if (err < 0)
2687 goto err_free;
2688 dsi->info.dsi_late_resume_cmd = p_late_resume_cmd;
2689 }
2690
2691 /* Copy panel suspend cmd */
2692 err = tegra_dc_dsi_cp_p_cmd(p_dsi->dsi_suspend_cmd, p_suspend_cmd,
2693 p_dsi->n_suspend_cmd);
2694 if (err < 0)
2695 goto err_free;
2696 dsi->info.dsi_suspend_cmd = p_suspend_cmd;
2697
2698 if (!dsi->info.panel_reset_timeout_msec)
2699 dsi->info.panel_reset_timeout_msec =
2700 DEFAULT_PANEL_RESET_TIMEOUT;
2701
2702 if (!dsi->info.panel_buffer_size_byte)
2703 dsi->info.panel_buffer_size_byte = DEFAULT_PANEL_BUFFER_BYTE;
2704
2705 if (!dsi->info.max_panel_freq_khz) {
2706 dsi->info.max_panel_freq_khz = DEFAULT_MAX_DSI_PHY_CLK_KHZ;
2707
2708 if (dsi->info.video_burst_mode >
2709 TEGRA_DSI_VIDEO_NONE_BURST_MODE_WITH_SYNC_END){
2710 dev_err(&dsi->dc->ndev->dev, "DSI: max_panel_freq_khz"
2711 "is not set for DSI burst mode.\n");
2712 dsi->info.video_burst_mode =
2713 TEGRA_DSI_VIDEO_BURST_MODE_LOWEST_SPEED;
2714 }
2715 }
2716
2717 if (!dsi->info.lp_cmd_mode_freq_khz)
2718 dsi->info.lp_cmd_mode_freq_khz = DEFAULT_LP_CMD_MODE_CLK_KHZ;
2719
2720 if (!dsi->info.chip_id || !dsi->info.chip_rev)
2721 dev_warn(&dsi->dc->ndev->dev,
2722 "DSI: Failed to get chip info\n");
2723
2724 if (!dsi->info.lp_read_cmd_mode_freq_khz)
2725 dsi->info.lp_read_cmd_mode_freq_khz =
2726 dsi->info.lp_cmd_mode_freq_khz;
2727
2728 /* host mode is for testing only */
2729 dsi->driven_mode = TEGRA_DSI_DRIVEN_BY_DC;
2730 return 0;
2731
2732err_free:
2733 kfree(p_suspend_cmd);
2734err_free_p_late_resume_cmd:
2735 kfree(p_late_resume_cmd);
2736err_free_p_early_suspend_cmd:
2737 kfree(p_early_suspend_cmd);
2738err_free_init_cmd:
2739 kfree(p_init_cmd);
2740 return err;
2741}
2742
2743static int tegra_dc_dsi_init(struct tegra_dc *dc)
2744{
2745 struct tegra_dc_dsi_data *dsi;
2746 struct resource *res;
2747 struct resource *base_res;
2748 void __iomem *base;
2749 struct clk *dc_clk = NULL;
2750 struct clk *dsi_clk = NULL;
2751 struct tegra_dsi_out *dsi_pdata;
2752 int err;
2753
2754 err = 0;
2755
2756 dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
2757 if (!dsi)
2758 return -ENOMEM;
2759
2760 res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM,
2761 "dsi_regs");
2762 if (!res) {
2763 dev_err(&dc->ndev->dev, "dsi: no mem resource\n");
2764 err = -ENOENT;
2765 goto err_free_dsi;
2766 }
2767
2768 base_res = request_mem_region(res->start, resource_size(res),
2769 dc->ndev->name);
2770 if (!base_res) {
2771 dev_err(&dc->ndev->dev, "dsi: request_mem_region failed\n");
2772 err = -EBUSY;
2773 goto err_free_dsi;
2774 }
2775
2776 base = ioremap(res->start, resource_size(res));
2777 if (!base) {
2778 dev_err(&dc->ndev->dev, "dsi: registers can't be mapped\n");
2779 err = -EBUSY;
2780 goto err_release_regs;
2781 }
2782
2783 dsi_pdata = dc->pdata->default_out->dsi;
2784 if (!dsi_pdata) {
2785 dev_err(&dc->ndev->dev, "dsi: dsi data not available\n");
2786 goto err_release_regs;
2787 }
2788
2789 if (dsi_pdata->dsi_instance)
2790 dsi_clk = clk_get(&dc->ndev->dev, "dsib");
2791 else
2792 dsi_clk = clk_get(&dc->ndev->dev, "dsia");
2793
2794 if (IS_ERR_OR_NULL(dsi_clk)) {
2795 dev_err(&dc->ndev->dev, "dsi: can't get clock\n");
2796 err = -EBUSY;
2797 goto err_release_regs;
2798 }
2799
2800 dc_clk = clk_get_sys(dev_name(&dc->ndev->dev), NULL);
2801 if (IS_ERR_OR_NULL(dc_clk)) {
2802 dev_err(&dc->ndev->dev, "dsi: dc clock %s unavailable\n",
2803 dev_name(&dc->ndev->dev));
2804 err = -EBUSY;
2805 goto err_clk_put;
2806 }
2807
2808 mutex_init(&dsi->lock);
2809 dsi->dc = dc;
2810 dsi->base = base;
2811 dsi->base_res = base_res;
2812 dsi->dc_clk = dc_clk;
2813 dsi->dsi_clk = dsi_clk;
2814
2815 err = tegra_dc_dsi_cp_info(dsi, dsi_pdata);
2816 if (err < 0)
2817 goto err_dsi_data;
2818
2819 tegra_dc_set_outdata(dc, dsi);
2820 _tegra_dc_dsi_init(dc);
2821
2822 return 0;
2823
2824err_dsi_data:
2825err_clk_put:
2826 clk_put(dsi_clk);
2827err_release_regs:
2828 release_resource(base_res);
2829err_free_dsi:
2830 kfree(dsi);
2831
2832 return err;
2833}
2834
2835static void tegra_dc_dsi_destroy(struct tegra_dc *dc)
2836{
2837 struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
2838 u16 i;
2839 u32 val;
2840
2841 mutex_lock(&dsi->lock);
2842
2843 /* free up the pdata */
2844 for (i = 0; i < dsi->info.n_init_cmd; i++) {
2845 if (dsi->info.dsi_init_cmd[i].pdata)
2846 kfree(dsi->info.dsi_init_cmd[i].pdata);
2847 }
2848 kfree(dsi->info.dsi_init_cmd);
2849
2850 /* Disable dc stream */
2851 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
2852 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
2853
2854 /* Disable dsi phy clock */
2855 if (dsi->status.clk_out == DSI_PHYCLK_OUT_EN)
2856 tegra_dsi_hs_clk_out_disable(dc, dsi);
2857
2858 val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
2859 tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
2860
2861 iounmap(dsi->base);
2862 release_resource(dsi->base_res);
2863
2864 clk_put(dsi->dc_clk);
2865 clk_put(dsi->dsi_clk);
2866
2867 mutex_unlock(&dsi->lock);
2868
2869 mutex_destroy(&dsi->lock);
2870 kfree(dsi);
2871}
2872
2873static int tegra_dsi_deep_sleep(struct tegra_dc *dc,
2874 struct tegra_dc_dsi_data *dsi)
2875{
2876 int err = 0;
2877 int val;
2878 struct clk *parent_clk = NULL;
2879 struct clk *base_clk = NULL;
2880
2881 if (!dsi->enabled) {
2882 err = -EPERM;
2883 goto fail;
2884 }
2885
2886 err = tegra_dsi_set_to_lp_mode(dc, dsi, DSI_LP_OP_WRITE);
2887 if (err < 0) {
2888 dev_err(&dc->ndev->dev,
2889 "DSI failed to go to LP mode\n");
2890 goto fail;
2891 }
2892
2893 /* Suspend panel */
2894 err = tegra_dsi_send_panel_cmd(dc, dsi,
2895 dsi->info.dsi_suspend_cmd,
2896 dsi->info.n_suspend_cmd);
2897 if (err < 0) {
2898 dev_err(&dc->ndev->dev,
2899 "dsi: Error sending suspend cmd\n");
2900 goto fail;
2901 }
2902
2903 if (!dsi->ulpm) {
2904 err = tegra_dsi_enter_ulpm(dsi);
2905 if (err < 0) {
2906 dev_err(&dc->ndev->dev,
2907 "DSI failed to enter ulpm\n");
2908 goto fail;
2909 }
2910 }
2911
2912 /*
2913 * Suspend pad
2914 * It is ok to overwrite previous value of DSI_PAD_CONTROL reg
2915 * because it will be restored properly in resume sequence
2916 */
2917 val = DSI_PAD_CONTROL_PAD_PDIO(0x3) |
2918 DSI_PAD_CONTROL_PAD_PDIO_CLK(0x1) |
2919 DSI_PAD_CONTROL_PAD_PULLDN_ENAB(TEGRA_DSI_ENABLE);
2920 tegra_dsi_writel(dsi, val, DSI_PAD_CONTROL);
2921
2922 /* Suspend core-logic */
2923 val = DSI_POWER_CONTROL_LEG_DSI_ENABLE(TEGRA_DSI_DISABLE);
2924 tegra_dsi_writel(dsi, val, DSI_POWER_CONTROL);
2925
2926 /* Disable dsi fast and slow clock */
2927 parent_clk = clk_get_parent(dsi->dsi_clk);
2928 base_clk = clk_get_parent(parent_clk);
2929 if (dsi->info.dsi_instance)
2930 tegra_clk_cfg_ex(base_clk,
2931 TEGRA_CLK_PLLD_CSI_OUT_ENB,
2932 0);
2933 else
2934 tegra_clk_cfg_ex(base_clk,
2935 TEGRA_CLK_PLLD_DSI_OUT_ENB,
2936 0);
2937
2938 /* Disable dsi source clock */
2939 clk_disable(dsi->dsi_clk);
2940
2941 dsi->clk_ref = false;
2942 dsi->enabled = false;
2943
2944 return 0;
2945fail:
2946 return err;
2947}
2948
2949static void tegra_dc_dsi_disable(struct tegra_dc *dc)
2950{
2951 int err;
2952 struct tegra_dc_dsi_data *dsi = tegra_dc_get_outdata(dc);
2953
2954 tegra_dc_io_start(dc);
2955 mutex_lock(&dsi->lock);
2956
2957 if (dsi->status.dc_stream == DSI_DC_STREAM_ENABLE)
2958 tegra_dsi_stop_dc_stream_at_frame_end(dc, dsi);
2959
2960 if (dsi->info.power_saving_suspend) {
2961 if (tegra_dsi_deep_sleep(dc, dsi) < 0) {
2962 dev_err(&dc->ndev->dev,
2963 "DSI failed to enter deep sleep\n");
2964 goto fail;
2965 }
2966 } else {
2967 if (dsi->info.dsi_early_suspend_cmd) {
2968 err = tegra_dsi_send_panel_cmd(dc, dsi,
2969 dsi->info.dsi_early_suspend_cmd,
2970 dsi->info.n_early_suspend_cmd);
2971 if (err < 0) {
2972 dev_err(&dc->ndev->dev,
2973 "dsi: Error sending early suspend cmd\n");
2974 goto fail;
2975 }
2976 }
2977
2978 if (!dsi->ulpm) {
2979 if (tegra_dsi_enter_ulpm(dsi) < 0) {
2980 dev_err(&dc->ndev->dev,
2981 "DSI failed to enter ulpm\n");
2982 goto fail;
2983 }
2984 }
2985 }
2986
2987fail:
2988 mutex_unlock(&dsi->lock);
2989 tegra_dc_io_end(dc);
2990}
2991
2992#ifdef CONFIG_PM
2993static void tegra_dc_dsi_suspend(struct tegra_dc *dc)
2994{
2995 struct tegra_dc_dsi_data *dsi;
2996
2997 dsi = tegra_dc_get_outdata(dc);
2998
2999 if (!dsi->enabled)
3000 return;
3001
3002 tegra_dc_io_start(dc);
3003 mutex_lock(&dsi->lock);
3004
3005 if (!dsi->info.power_saving_suspend) {
3006 if (dsi->ulpm) {
3007 if (tegra_dsi_exit_ulpm(dsi) < 0) {
3008 dev_err(&dc->ndev->dev,
3009 "DSI failed to exit ulpm");
3010 goto fail;
3011 }
3012 }
3013
3014 if (tegra_dsi_deep_sleep(dc, dsi) < 0) {
3015 dev_err(&dc->ndev->dev,
3016 "DSI failed to enter deep sleep\n");
3017 goto fail;
3018 }
3019 }
3020fail:
3021 mutex_unlock(&dsi->lock);
3022 tegra_dc_io_end(dc);
3023}
3024
3025static void tegra_dc_dsi_resume(struct tegra_dc *dc)
3026{
3027 /* Not required since tegra_dc_dsi_enable
3028 * will reconfigure the controller from scratch
3029 */
3030}
3031#endif
3032
3033struct tegra_dc_out_ops tegra_dc_dsi_ops = {
3034 .init = tegra_dc_dsi_init,
3035 .destroy = tegra_dc_dsi_destroy,
3036 .enable = tegra_dc_dsi_enable,
3037 .disable = tegra_dc_dsi_disable,
3038#ifdef CONFIG_PM
3039 .suspend = tegra_dc_dsi_suspend,
3040 .resume = tegra_dc_dsi_resume,
3041#endif
3042};
diff --git a/drivers/video/tegra/dc/dsi.h b/drivers/video/tegra/dc/dsi.h
new file mode 100644
index 00000000000..18ea9c959e8
--- /dev/null
+++ b/drivers/video/tegra/dc/dsi.h
@@ -0,0 +1,375 @@
1/*
2 * drivers/video/tegra/dc/dsi.h
3 *
4 * Copyright (c) 2011, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __DRIVERS_VIDEO_TEGRA_DC_DSI_H__
18#define __DRIVERS_VIDEO_TEGRA_DC_DSI_H__
19
20/* source of video data */
21enum {
22 TEGRA_DSI_VIDEO_DRIVEN_BY_DC,
23 TEGRA_DSI_VIDEO_DRIVEN_BY_HOST,
24};
25
26/* Max number of data lanes supported */
27#define MAX_DSI_DATA_LANES 2
28/* Default Peripheral reset timeout */
29#define DSI_PR_TO_VALUE 0x2000
30
31/* DCS commands for command mode */
32#define DSI_ENTER_PARTIAL_MODE 0x12
33#define DSI_SET_PIXEL_FORMAT 0x3A
34#define DSI_AREA_COLOR_MODE 0x4C
35#define DSI_SET_PARTIAL_AREA 0x30
36#define DSI_SET_PAGE_ADDRESS 0x2B
37#define DSI_SET_ADDRESS_MODE 0x36
38#define DSI_SET_COLUMN_ADDRESS 0x2A
39#define DSI_WRITE_MEMORY_START 0x2C
40#define DSI_WRITE_MEMORY_CONTINUE 0x3C
41#define DSI_MAX_COMMAND_DELAY_USEC 250000
42#define DSI_COMMAND_DELAY_STEPS_USEC 10
43
44/* Trigger message */
45#define DSI_ESCAPE_CMD 0x87
46#define DSI_ACK_NO_ERR 0x84
47
48/* DSI return packet types */
49#define GEN_LONG_RD_RES 0x1A
50#define DCS_LONG_RD_RES 0x1C
51#define GEN_1_BYTE_SHORT_RD_RES 0x11
52#define DCS_1_BYTE_SHORT_RD_RES 0x21
53#define GEN_2_BYTE_SHORT_RD_RES 0x12
54#define DCS_2_BYTE_SHORT_RD_RES 0x22
55#define ACK_ERR_RES 0x02
56
57/* End of Transmit command for HS mode */
58#define DSI_CMD_HS_EOT_PACKAGE 0x000F0F08
59
60/* Delay required after issuing the trigger*/
61#define DSI_COMMAND_COMPLETION_DELAY_USEC 5
62
63#define DSI_DELAY_FOR_READ_FIFO 5
64
65/* Dsi virtual channel bit position, refer to the DSI specs */
66#define DSI_VIR_CHANNEL_BIT_POSITION 6
67
68/* DSI packet commands from Host to peripherals */
69enum {
70 dsi_command_v_sync_start = 0x01,
71 dsi_command_v_sync_end = 0x11,
72 dsi_command_h_sync_start = 0x21,
73 dsi_command_h_sync_end = 0x31,
74 dsi_command_end_of_transaction = 0x08,
75 dsi_command_blanking = 0x19,
76 dsi_command_null_packet = 0x09,
77 dsi_command_h_active_length_16bpp = 0x0E,
78 dsi_command_h_active_length_18bpp = 0x1E,
79 dsi_command_h_active_length_18bpp_np = 0x2E,
80 dsi_command_h_active_length_24bpp = 0x3E,
81 dsi_command_h_sync_active = dsi_command_blanking,
82 dsi_command_h_back_porch = dsi_command_blanking,
83 dsi_command_h_front_porch = dsi_command_blanking,
84 dsi_command_writ_no_param = 0x05,
85 dsi_command_long_write = 0x39,
86 dsi_command_max_return_pkt_size = 0x37,
87 dsi_command_generic_read_request_with_2_param = 0x24,
88 dsi_command_dcs_read_with_no_params = 0x06,
89};
90
91/* Maximum polling time for reading the dsi status register */
92#define DSI_STATUS_POLLING_DURATION_USEC 100000
93#define DSI_STATUS_POLLING_DELAY_USEC 100
94
95/*
96 * Horizontal Sync Blank Packet Over head
97 * DSI_overhead = size_of(HS packet header)
98 * + size_of(BLANK packet header) + size_of(checksum)
99 * DSI_overhead = 4 + 4 + 2 = 10
100 */
101#define DSI_HSYNC_BLNK_PKT_OVERHEAD 10
102
103/*
104 * Horizontal Front Porch Packet Overhead
105 * DSI_overhead = size_of(checksum)
106 * + size_of(BLANK packet header) + size_of(checksum)
107 * DSI_overhead = 2 + 4 + 2 = 8
108 */
109#define DSI_HFRONT_PORCH_PKT_OVERHEAD 8
110
111/*
112 * Horizontal Back Porch Packet
113 * DSI_overhead = size_of(HE packet header)
114 * + size_of(BLANK packet header) + size_of(checksum)
115 * + size_of(RGB packet header)
116 * DSI_overhead = 4 + 4 + 2 + 4 = 14
117 */
118#define DSI_HBACK_PORCH_PKT_OVERHEAD 14
119
120/* Additional Hs TX timeout margin */
121#define DSI_HTX_TO_MARGIN 720
122
123#define DSI_CYCLE_COUNTER_VALUE 512
124
125#define DSI_LRXH_TO_VALUE 0x2000
126
127/* Turn around timeout terminal count */
128#define DSI_TA_TO_VALUE 0x2000
129
130/* Turn around timeout tally */
131#define DSI_TA_TALLY_VALUE 0x0
132/* LP Rx timeout tally */
133#define DSI_LRXH_TALLY_VALUE 0x0
134/* HS Tx Timeout tally */
135#define DSI_HTX_TALLY_VALUE 0x0
136
137/* DSI Power control settle time 10 micro seconds */
138#define DSI_POWER_CONTROL_SETTLE_TIME_US 10
139
140#define DSI_HOST_FIFO_DEPTH 64
141#define DSI_VIDEO_FIFO_DEPTH 480
142#define DSI_READ_FIFO_DEPTH (32 << 2)
143
144#define NUMOF_BIT_PER_BYTE 8
145#define DEFAULT_LP_CMD_MODE_CLK_KHZ 10000
146#define DEFAULT_MAX_DSI_PHY_CLK_KHZ (500*1000)
147#define DEFAULT_PANEL_RESET_TIMEOUT 2
148#define DEFAULT_PANEL_BUFFER_BYTE 512
149
150/*
151 * TODO: are DSI_HOST_DSI_CONTROL_CRC_RESET(RESET_CRC) and
152 * DSI_HOST_DSI_CONTROL_HOST_TX_TRIG_SRC(IMMEDIATE) required for everyone?
153 */
154#define HOST_DSI_CTRL_COMMON \
155 (DSI_HOST_DSI_CONTROL_PHY_CLK_DIV(DSI_PHY_CLK_DIV1) | \
156 DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(NORMAL) | \
157 DSI_HOST_DSI_CONTROL_PERIPH_RESET(TEGRA_DSI_DISABLE) | \
158 DSI_HOST_DSI_CONTROL_RAW_DATA(TEGRA_DSI_DISABLE) | \
159 DSI_HOST_DSI_CONTROL_IMM_BTA(TEGRA_DSI_DISABLE) | \
160 DSI_HOST_DSI_CONTROL_PKT_BTA(TEGRA_DSI_DISABLE) | \
161 DSI_HOST_DSI_CONTROL_CS_ENABLE(TEGRA_DSI_ENABLE) | \
162 DSI_HOST_DSI_CONTROL_ECC_ENABLE(TEGRA_DSI_ENABLE) | \
163 DSI_HOST_DSI_CONTROL_PKT_WR_FIFO_SEL(HOST_ONLY))
164
165#define HOST_DSI_CTRL_HOST_DRIVEN \
166 (DSI_HOST_DSI_CONTROL_CRC_RESET(RESET_CRC) | \
167 DSI_HOST_DSI_CONTROL_HOST_TX_TRIG_SRC(IMMEDIATE))
168
169#define HOST_DSI_CTRL_DC_DRIVEN 0
170
171#define DSI_CTRL_HOST_DRIVEN (DSI_CONTROL_VID_ENABLE(TEGRA_DSI_DISABLE) | \
172 DSI_CONTROL_HOST_ENABLE(TEGRA_DSI_ENABLE))
173
174#define DSI_CTRL_DC_DRIVEN (DSI_CONTROL_VID_TX_TRIG_SRC(SOL) | \
175 DSI_CONTROL_VID_ENABLE(TEGRA_DSI_ENABLE) | \
176 DSI_CONTROL_HOST_ENABLE(TEGRA_DSI_DISABLE))
177
178#define DSI_CTRL_CMD_MODE (DSI_CONTROL_VID_DCS_ENABLE(TEGRA_DSI_ENABLE))
179
180#define DSI_CTRL_VIDEO_MODE (DSI_CONTROL_VID_DCS_ENABLE(TEGRA_DSI_DISABLE))
181
182
183enum {
184 CMD_VS = 0x01,
185 CMD_VE = 0x11,
186
187 CMD_HS = 0x21,
188 CMD_HE = 0x31,
189
190 CMD_EOT = 0x08,
191 CMD_NULL = 0x09,
192 CMD_SHORTW = 0x15,
193 CMD_BLNK = 0x19,
194 CMD_LONGW = 0x39,
195
196 CMD_RGB = 0x00,
197 CMD_RGB_16BPP = 0x0E,
198 CMD_RGB_18BPP = 0x1E,
199 CMD_RGB_18BPPNP = 0x2E,
200 CMD_RGB_24BPP = 0x3E,
201};
202
203#define PKT_ID0(id) (DSI_PKT_SEQ_0_LO_PKT_00_ID(id) | \
204 DSI_PKT_SEQ_1_LO_PKT_10_EN(TEGRA_DSI_ENABLE))
205#define PKT_LEN0(len) (DSI_PKT_SEQ_0_LO_PKT_00_SIZE(len))
206
207#define PKT_ID1(id) (DSI_PKT_SEQ_0_LO_PKT_01_ID(id) | \
208 DSI_PKT_SEQ_1_LO_PKT_11_EN(TEGRA_DSI_ENABLE))
209#define PKT_LEN1(len) (DSI_PKT_SEQ_0_LO_PKT_01_SIZE(len))
210
211#define PKT_ID2(id) (DSI_PKT_SEQ_0_LO_PKT_02_ID(id) | \
212 DSI_PKT_SEQ_1_LO_PKT_12_EN(TEGRA_DSI_ENABLE))
213#define PKT_LEN2(len) (DSI_PKT_SEQ_0_LO_PKT_02_SIZE(len))
214
215#define PKT_ID3(id) (DSI_PKT_SEQ_0_HI_PKT_03_ID(id) | \
216 DSI_PKT_SEQ_1_HI_PKT_13_EN(TEGRA_DSI_ENABLE))
217#define PKT_LEN3(len) (DSI_PKT_SEQ_0_HI_PKT_03_SIZE(len))
218
219#define PKT_ID4(id) (DSI_PKT_SEQ_0_HI_PKT_04_ID(id) | \
220 DSI_PKT_SEQ_1_HI_PKT_14_EN(TEGRA_DSI_ENABLE))
221#define PKT_LEN4(len) (DSI_PKT_SEQ_0_HI_PKT_04_SIZE(len))
222
223#define PKT_ID5(id) (DSI_PKT_SEQ_0_HI_PKT_05_ID(id) | \
224 DSI_PKT_SEQ_1_HI_PKT_15_EN(TEGRA_DSI_ENABLE))
225#define PKT_LEN5(len) (DSI_PKT_SEQ_0_HI_PKT_05_SIZE(len))
226
227#define PKT_LP (DSI_PKT_SEQ_0_LO_SEQ_0_FORCE_LP(TEGRA_DSI_ENABLE))
228
229#define NUMOF_PKT_SEQ 12
230
231/* Mipi v1.00.00 phy timing range */
232#define NOT_DEFINED -1
233#define MIPI_T_HSEXIT_NS_MIN 100
234#define MIPI_T_HSEXIT_NS_MAX NOT_DEFINED
235#define MIPI_T_HSTRAIL_NS_MIN(clk_ns) max((8 * (clk_ns)), (60 + 4 * (clk_ns)))
236#define MIPI_T_HSTRAIL_NS_MAX NOT_DEFINED
237#define MIPI_T_HSZERO_NS_MIN NOT_DEFINED
238#define MIPI_T_HSZERO_NS_MAX NOT_DEFINED
239#define MIPI_T_HSPREPARE_NS_MIN(clk_ns) (40 + 4 * (clk_ns))
240#define MIPI_T_HSPREPARE_NS_MAX(clk_ns) (85 + 6 * (clk_ns))
241#define MIPI_T_CLKTRAIL_NS_MIN 60
242#define MIPI_T_CLKTRAIL_NS_MAX NOT_DEFINED
243#define MIPI_T_CLKPOST_NS_MIN(clk_ns) (60 + 52 * (clk_ns))
244#define MIPI_T_CLKPOST_NS_MAX NOT_DEFINED
245#define MIPI_T_CLKZERO_NS_MIN NOT_DEFINED
246#define MIPI_T_CLKZERO_NS_MAX NOT_DEFINED
247#define MIPI_T_TLPX_NS_MIN 50
248#define MIPI_T_TLPX_NS_MAX NOT_DEFINED
249#define MIPI_T_CLKPREPARE_NS_MIN 38
250#define MIPI_T_CLKPREPARE_NS_MAX 95
251#define MIPI_T_CLKPRE_NS_MIN 8
252#define MIPI_T_CLKPRE_NS_MAX NOT_DEFINED
253#define MIPI_T_WAKEUP_NS_MIN 1
254#define MIPI_T_WAKEUP_NS_MAX NOT_DEFINED
255#define MIPI_T_TASURE_NS_MIN(tlpx_ns) (tlpx_ns)
256#define MIPI_T_TASURE_NS_MAX(tlpx_ns) (2 * (tlpx_ns))
257#define MIPI_T_HSPREPARE_ADD_HSZERO_NS_MIN(clk_ns) (145 + 10 * (clk_ns))
258#define MIPI_T_HSPREPARE_ADD_HSZERO_NS_MAX NOT_DEFINED
259#define MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MIN 300
260#define MIPI_T_CLKPREPARE_ADD_CLKZERO_NS_MAX NOT_DEFINED
261
262#define DSI_TBYTE(clk_ns) ((clk_ns) * (BITS_PER_BYTE))
263#define DSI_CONVERT_T_PHY_NS_TO_T_PHY(t_phy_ns, clk_ns, hw_inc) \
264 ((int)((DIV_ROUND_CLOSEST((t_phy_ns), \
265 (DSI_TBYTE(clk_ns)))) - (hw_inc)))
266
267#define DSI_CONVERT_T_PHY_TO_T_PHY_NS(t_phy, clk_ns, hw_inc) \
268 (((t_phy) + (hw_inc)) * (DSI_TBYTE(clk_ns)))
269
270/* Default phy timing in ns */
271#define T_HSEXIT_NS_DEFAULT 120
272#define T_HSTRAIL_NS_DEFAULT(clk_ns) \
273 max((8 * (clk_ns)), (60 + 4 * (clk_ns)))
274
275#define T_DATZERO_NS_DEFAULT(clk_ns) (145 + 5 * (clk_ns))
276#define T_HSPREPARE_NS_DEFAULT(clk_ns) (65 + 5 * (clk_ns))
277#define T_CLKTRAIL_NS_DEFAULT 80
278#define T_CLKPOST_NS_DEFAULT(clk_ns) (70 + 52 * (clk_ns))
279#define T_CLKZERO_NS_DEFAULT 260
280#define T_TLPX_NS_DEFAULT 60
281#define T_CLKPREPARE_NS_DEFAULT 65
282#define T_TAGO_NS_DEFAULT (4 * (T_TLPX_NS_DEFAULT))
283#define T_TASURE_NS_DEFAULT (2 * (T_TLPX_NS_DEFAULT))
284#define T_TAGET_NS_DEFAULT (5 * (T_TLPX_NS_DEFAULT))
285
286/* HW increment to phy register values */
287#define T_HSEXIT_HW_INC 1
288#define T_HSTRAIL_HW_INC 0
289#define T_DATZERO_HW_INC 3
290#define T_HSPREPARE_HW_INC 1
291#define T_CLKTRAIL_HW_INC 1
292#define T_CLKPOST_HW_INC 1
293#define T_CLKZERO_HW_INC 1
294#define T_TLPX_HW_INC 1
295#define T_CLKPREPARE_HW_INC 1
296#define T_TAGO_HW_INC 1
297#define T_TASURE_HW_INC 1
298#define T_TAGET_HW_INC 1
299#define T_CLKPRE_HW_INC 1
300#define T_WAKEUP_HW_INC 1
301
302/* Default phy timing reg values */
303#define T_HSEXIT_DEFAULT(clk_ns) \
304(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
305T_HSEXIT_NS_DEFAULT, clk_ns, T_HSEXIT_HW_INC))
306
307#define T_HSTRAIL_DEFAULT(clk_ns) \
308(3 + (DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
309T_HSTRAIL_NS_DEFAULT(clk_ns), clk_ns, T_HSTRAIL_HW_INC)))
310
311#define T_DATZERO_DEFAULT(clk_ns) \
312(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
313T_DATZERO_NS_DEFAULT(clk_ns), clk_ns, T_DATZERO_HW_INC))
314
315#define T_HSPREPARE_DEFAULT(clk_ns) \
316(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
317T_HSPREPARE_NS_DEFAULT(clk_ns), clk_ns, T_HSPREPARE_HW_INC))
318
319#define T_CLKTRAIL_DEFAULT(clk_ns) \
320(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
321T_CLKTRAIL_NS_DEFAULT, clk_ns, T_CLKTRAIL_HW_INC))
322
323#define T_CLKPOST_DEFAULT(clk_ns) \
324(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
325T_CLKPOST_NS_DEFAULT(clk_ns), clk_ns, T_CLKPOST_HW_INC))
326
327#define T_CLKZERO_DEFAULT(clk_ns) \
328(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
329T_CLKZERO_NS_DEFAULT, clk_ns, T_CLKZERO_HW_INC))
330
331#define T_TLPX_DEFAULT(clk_ns) \
332(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
333T_TLPX_NS_DEFAULT, clk_ns, T_TLPX_HW_INC))
334
335#define T_CLKPREPARE_DEFAULT(clk_ns) \
336(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
337T_CLKPREPARE_NS_DEFAULT, clk_ns, T_CLKPREPARE_HW_INC))
338
339#define T_CLKPRE_DEFAULT 0x1
340#define T_WAKEUP_DEFAULT 0x7f
341
342#define T_TAGO_DEFAULT(clk_ns) \
343(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
344T_TAGO_NS_DEFAULT, clk_ns, T_TAGO_HW_INC))
345
346#define T_TASURE_DEFAULT(clk_ns) \
347(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
348T_TASURE_NS_DEFAULT, clk_ns, T_TASURE_HW_INC))
349
350#define T_TAGET_DEFAULT(clk_ns) \
351(DSI_CONVERT_T_PHY_NS_TO_T_PHY( \
352T_TAGET_NS_DEFAULT, clk_ns, T_TAGET_HW_INC))
353
354/* Defines the DSI phy timing parameters */
355struct dsi_phy_timing_inclk {
356 unsigned t_hsdexit;
357 unsigned t_hstrail;
358 unsigned t_hsprepare;
359 unsigned t_datzero;
360
361 unsigned t_clktrail;
362 unsigned t_clkpost;
363 unsigned t_clkzero;
364 unsigned t_tlpx;
365
366 unsigned t_clkpre;
367 unsigned t_clkprepare;
368 unsigned t_wakeup;
369
370 unsigned t_taget;
371 unsigned t_tasure;
372 unsigned t_tago;
373};
374
375#endif
diff --git a/drivers/video/tegra/dc/dsi_regs.h b/drivers/video/tegra/dc/dsi_regs.h
new file mode 100644
index 00000000000..203ac32bd92
--- /dev/null
+++ b/drivers/video/tegra/dc/dsi_regs.h
@@ -0,0 +1,351 @@
1/*
2 * drivers/video/tegra/dc/dsi_regs.h
3 *
4 * Copyright (c) 2011, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __DRIVERS_VIDEO_TEGRA_DC_DSI_REG_H__
18#define __DRIVERS_VIDEO_TEGRA_DC_DSI_REG_H__
19
20enum {
21 TEGRA_DSI_DISABLE,
22 TEGRA_DSI_ENABLE,
23};
24
25/* These are word offsets from base (not byte offsets) */
26enum {
27 OP_DONE = 1,
28};
29#define DSI_INCR_SYNCPT 0x00
30#define DSI_INCR_SYNCPT_COND(x) (((x) & 0xff) << 8)
31#define DSI_INCR_SYNCPT_INDX(x) (((x) & 0xff) << 0)
32
33#define DSI_INCR_SYNCPT_CNTRL 0x01
34#define DSI_INCR_SYNCPT_ERROR 0x02
35#define DSI_CTXSW 0x08
36#define DSI_RD_DATA 0x09
37#define DSI_WR_DATA 0x0a
38
39#define DSI_POWER_CONTROL 0x0b
40#define DSI_POWER_CONTROL_LEG_DSI_ENABLE(x) (((x) & 0x1) << 0)
41
42#define DSI_INT_ENABLE 0x0c
43#define DSI_INT_STATUS 0x0d
44#define DSI_INT_MASK 0x0e
45
46#define DSI_HOST_DSI_CONTROL 0x0f
47enum {
48 RESET_CRC = 1,
49};
50#define DSI_HOST_CONTROL_FIFO_STAT_RESET(x) (((x) & 0x1) << 21)
51#define DSI_HOST_DSI_CONTROL_CRC_RESET(x) (((x) & 0x1) << 20)
52enum {
53 DSI_PHY_CLK_DIV1,
54 DSI_PHY_CLK_DIV2,
55};
56#define DSI_HOST_DSI_CONTROL_PHY_CLK_DIV(x) (((x) & 0x7) << 16)
57enum {
58 SOL,
59 FIFO_LEVEL,
60 IMMEDIATE,
61};
62#define DSI_HOST_DSI_CONTROL_HOST_TX_TRIG_SRC(x) (((x) & 0x3) << 12)
63enum {
64 NORMAL,
65 ENTER_ULPM,
66 EXIT_ULPM,
67};
68#define DSI_HOST_DSI_CONTROL_ULTRA_LOW_POWER(x) (((x) & 0x3) << 8)
69#define DSI_HOST_DSI_CONTROL_PERIPH_RESET(x) (((x) & 0x1) << 7)
70#define DSI_HOST_DSI_CONTROL_RAW_DATA(x) (((x) & 0x1) << 6)
71enum {
72 TEGRA_DSI_LOW,
73 TEGRA_DSI_HIGH,
74};
75#define DSI_HOST_DSI_CONTROL_HIGH_SPEED_TRANS(x) (((x) & 0x1) << 5)
76enum {
77 HOST_ONLY,
78 VIDEO_HOST,
79};
80#define DSI_HOST_DSI_CONTROL_PKT_WR_FIFO_SEL(x) (((x) & 0x1) << 4)
81#define DSI_HOST_DSI_CONTROL_IMM_BTA(x) (((x) & 0x1) << 3)
82#define DSI_HOST_DSI_CONTROL_PKT_BTA(x) (((x) & 0x1) << 2)
83#define DSI_HOST_DSI_CONTROL_CS_ENABLE(x) (((x) & 0x1) << 1)
84#define DSI_HOST_DSI_CONTROL_ECC_ENABLE(x) (((x) & 0x1) << 0)
85
86#define DSI_CONTROL 0x10
87#define DSI_CONTROL_DBG_ENABLE(x) (((x) & 0x1) << 31)
88enum {
89 CONTINUOUS,
90 TX_ONLY,
91};
92#define DSI_CONTROL_HS_CLK_CTRL(x) (((x) & 0x1) << 20)
93#define DSI_CONTROL_VIRTUAL_CHANNEL(x) (((x) & 0x3) << 16)
94#define DSI_CONTROL_DATA_FORMAT(x) (((x) & 0x3) << 12)
95#define DSI_CONTROL_VID_TX_TRIG_SRC(x) (((x) & 0x3) << 8)
96#define DSI_CONTROL_NUM_DATA_LANES(x) (((x) & 0x3) << 4)
97#define DSI_CONTROL_VID_DCS_ENABLE(x) (((x) & 0x1) << 3)
98#define DSI_CONTROL_VID_SOURCE(x) (((x) & 0x1) << 2)
99#define DSI_CONTROL_VID_ENABLE(x) (((x) & 0x1) << 1)
100#define DSI_CONTROL_HOST_ENABLE(x) (((x) & 0x1) << 0)
101
102#define DSI_SOL_DELAY 0x11
103#define DSI_SOL_DELAY_SOL_DELAY(x) (((x) & 0xffff) << 0)
104
105#define DSI_MAX_THRESHOLD 0x12
106#define DSI_MAX_THRESHOLD_MAX_THRESHOLD(x) (((x) & 0xffff) << 0)
107
108#define DSI_TRIGGER 0x13
109#define DSI_TRIGGER_HOST_TRIGGER(x) (((x) & 0x1) << 1)
110#define DSI_TRIGGER_VID_TRIGGER(x) (((x) & 0x1) << 0)
111
112#define DSI_TX_CRC 0x14
113#define DSI_TX_CRC_TX_CRC(x) (((x) & 0xffffffff) << 0)
114
115#define DSI_STATUS 0x15
116#define DSI_STATUS_IDLE(x) (((x) & 0x1) << 10)
117#define DSI_STATUS_LB_UNDERFLOW(x) (((x) & 0x1) << 9)
118#define DSI_STATUS_LB_OVERFLOW(x) (((x) & 0x1) << 8)
119#define DSI_STATUS_RD_FIFO_COUNT(x) (((x) & 0x1f) << 0)
120
121#define DSI_INIT_SEQ_CONTROL 0x1a
122#define DSI_INIT_SEQ_CONTROL_DSI_FRAME_INIT_BYTE_COUNT(x) \
123 (((x) & 0x3f) << 8)
124#define DSI_INIT_SEQ_CONTROL_DSI_SEND_INIT_SEQUENCE(x) \
125 (((x) & 0xff) << 0)
126
127#define DSI_INIT_SEQ_DATA_0 0x1b
128#define DSI_INIT_SEQ_DATA_1 0x1c
129#define DSI_INIT_SEQ_DATA_2 0x1d
130#define DSI_INIT_SEQ_DATA_3 0x1e
131#define DSI_INIT_SEQ_DATA_4 0x1f
132#define DSI_INIT_SEQ_DATA_5 0x20
133#define DSI_INIT_SEQ_DATA_6 0x21
134#define DSI_INIT_SEQ_DATA_7 0x22
135
136#define DSI_PKT_SEQ_0_LO 0x23
137#define DSI_PKT_SEQ_0_LO_SEQ_0_FORCE_LP(x) (((x) & 0x1) << 30)
138#define DSI_PKT_SEQ_0_LO_PKT_02_EN(x) (((x) & 0x1) << 29)
139#define DSI_PKT_SEQ_0_LO_PKT_02_ID(x) (((x) & 0x3f) << 23)
140#define DSI_PKT_SEQ_0_LO_PKT_02_SIZE(x) (((x) & 0x7) << 20)
141#define DSI_PKT_SEQ_0_LO_PKT_01_EN(x) (((x) & 0x1) << 19)
142#define DSI_PKT_SEQ_0_LO_PKT_01_ID(x) (((x) & 0x3f) << 13)
143#define DSI_PKT_SEQ_0_LO_PKT_01_SIZE(x) (((x) & 0x7) << 10)
144#define DSI_PKT_SEQ_0_LO_PKT_00_EN(x) (((x) & 0x1) << 9)
145#define DSI_PKT_SEQ_0_LO_PKT_00_ID(x) (((x) & 0x3f) << 3)
146#define DSI_PKT_SEQ_0_LO_PKT_00_SIZE(x) (((x) & 0x7) << 0)
147
148#define DSI_PKT_SEQ_0_HI 0x24
149#define DSI_PKT_SEQ_0_HI_PKT_05_EN(x) (((x) & 0x1) << 29)
150#define DSI_PKT_SEQ_0_HI_PKT_05_ID(x) (((x) & 0x3f) << 23)
151#define DSI_PKT_SEQ_0_HI_PKT_05_SIZE(x) (((x) & 0x7) << 20)
152#define DSI_PKT_SEQ_0_HI_PKT_04_EN(x) (((x) & 0x1) << 19)
153#define DSI_PKT_SEQ_0_HI_PKT_04_ID(x) (((x) & 0x3f) << 13)
154#define DSI_PKT_SEQ_0_HI_PKT_04_SIZE(x) (((x) & 0x7) << 10)
155#define DSI_PKT_SEQ_0_HI_PKT_03_EN(x) (((x) & 0x1) << 9)
156#define DSI_PKT_SEQ_0_HI_PKT_03_ID(x) (((x) & 0x3f) << 3)
157#define DSI_PKT_SEQ_0_HI_PKT_03_SIZE(x) (((x) & 0x7) << 0)
158
159#define DSI_PKT_SEQ_1_LO 0x25
160#define DSI_PKT_SEQ_1_LO_SEQ_1_FORCE_LP(x) (((x) & 0x1) << 30)
161#define DSI_PKT_SEQ_1_LO_PKT_12_EN(x) (((x) & 0x1) << 29)
162#define DSI_PKT_SEQ_1_LO_PKT_12_ID(x) (((x) & 0x3f) << 23)
163#define DSI_PKT_SEQ_1_LO_PKT_12_SIZE(x) (((x) & 0x7) << 20)
164#define DSI_PKT_SEQ_1_LO_PKT_11_EN(x) (((x) & 0x1) << 19)
165#define DSI_PKT_SEQ_1_LO_PKT_11_ID(x) (((x) & 0x3f) << 13)
166#define DSI_PKT_SEQ_1_LO_PKT_11_SIZE(x) (((x) & 0x7) << 10)
167#define DSI_PKT_SEQ_1_LO_PKT_10_EN(x) (((x) & 0x1) << 9)
168#define DSI_PKT_SEQ_1_LO_PKT_10_ID(x) (((x) & 0x3f) << 3)
169#define DSI_PKT_SEQ_1_LO_PKT_10_SIZE(x) (((x) & 0x7) << 0)
170
171#define DSI_PKT_SEQ_1_HI 0x26
172#define DSI_PKT_SEQ_1_HI_PKT_15_EN(x) (((x) & 0x1) << 29)
173#define DSI_PKT_SEQ_1_HI_PKT_15_ID(x) (((x) & 0x3f) << 23)
174#define DSI_PKT_SEQ_1_HI_PKT_15_SIZE(x) (((x) & 0x7) << 20)
175#define DSI_PKT_SEQ_1_HI_PKT_14_EN(x) (((x) & 0x1) << 19)
176#define DSI_PKT_SEQ_1_HI_PKT_14_ID(x) (((x) & 0x3f) << 13)
177#define DSI_PKT_SEQ_1_HI_PKT_14_SIZE(x) (((x) & 0x7) << 10)
178#define DSI_PKT_SEQ_1_HI_PKT_13_EN(x) (((x) & 0x1) << 9)
179#define DSI_PKT_SEQ_1_HI_PKT_13_ID(x) (((x) & 0x3f) << 3)
180#define DSI_PKT_SEQ_1_HI_PKT_13_SIZE(x) (((x) & 0x7) << 0)
181
182#define DSI_PKT_SEQ_2_LO 0x27
183#define DSI_PKT_SEQ_2_LO_SEQ_2_FORCE_LP(x) (((x) & 0x1) << 30)
184#define DSI_PKT_SEQ_2_LO_PKT_22_EN(x) (((x) & 0x1) << 29)
185#define DSI_PKT_SEQ_2_LO_PKT_22_ID(x) (((x) & 0x3f) << 23)
186#define DSI_PKT_SEQ_2_LO_PKT_22_SIZE(x) (((x) & 0x7) << 20)
187#define DSI_PKT_SEQ_2_LO_PKT_21_EN(x) (((x) & 0x1) << 19)
188#define DSI_PKT_SEQ_2_LO_PKT_21_ID(x) (((x) & 0x3f) << 13)
189#define DSI_PKT_SEQ_2_LO_PKT_21_SIZE(x) (((x) & 0x7) << 10)
190#define DSI_PKT_SEQ_2_LO_PKT_20_EN(x) (((x) & 0x1) << 9)
191#define DSI_PKT_SEQ_2_LO_PKT_20_ID(x) (((x) & 0x3f) << 3)
192#define DSI_PKT_SEQ_2_LO_PKT_20_SIZE(x) (((x) & 0x7) << 0)
193
194#define DSI_PKT_SEQ_2_HI 0x28
195#define DSI_PKT_SEQ_2_HI_PKT_25_EN(x) (((x) & 0x1) << 29)
196#define DSI_PKT_SEQ_2_HI_PKT_25_ID(x) (((x) & 0x3f) << 23)
197#define DSI_PKT_SEQ_2_HI_PKT_25_SIZE(x) (((x) & 0x7) << 20)
198#define DSI_PKT_SEQ_2_HI_PKT_24_EN(x) (((x) & 0x1) << 19)
199#define DSI_PKT_SEQ_2_HI_PKT_24_ID(x) (((x) & 0x3f) << 13)
200#define DSI_PKT_SEQ_2_HI_PKT_24_SIZE(x) (((x) & 0x7) << 10)
201#define DSI_PKT_SEQ_2_HI_PKT_23_EN(x) (((x) & 0x1) << 9)
202#define DSI_PKT_SEQ_2_HI_PKT_23_ID(x) (((x) & 0x3f) << 3)
203#define DSI_PKT_SEQ_2_HI_PKT_23_SIZE(x) (((x) & 0x7) << 0)
204
205#define DSI_PKT_SEQ_3_LO 0x29
206#define DSI_PKT_SEQ_3_LO_SEQ_3_FORCE_LP(x) (((x) & 0x1) << 30)
207#define DSI_PKT_SEQ_3_LO_PKT_32_EN(x) (((x) & 0x1) << 29)
208#define DSI_PKT_SEQ_3_LO_PKT_32_ID(x) (((x) & 0x3f) << 23)
209#define DSI_PKT_SEQ_3_LO_PKT_32_SIZE(x) (((x) & 0x7) << 20)
210#define DSI_PKT_SEQ_3_LO_PKT_31_EN(x) (((x) & 0x1) << 19)
211#define DSI_PKT_SEQ_3_LO_PKT_31_ID(x) (((x) & 0x3f) << 13)
212#define DSI_PKT_SEQ_3_LO_PKT_31_SIZE(x) (((x) & 0x7) << 10)
213#define DSI_PKT_SEQ_3_LO_PKT_30_EN(x) (((x) & 0x1) << 9)
214#define DSI_PKT_SEQ_3_LO_PKT_30_ID(x) (((x) & 0x3f) << 3)
215#define DSI_PKT_SEQ_3_LO_PKT_30_SIZE(x) (((x) & 0x7) << 0)
216
217#define DSI_PKT_SEQ_3_HI 0x2a
218#define DSI_PKT_SEQ_3_HI_PKT_35_EN(x) (((x) & 0x1) << 29)
219#define DSI_PKT_SEQ_3_HI_PKT_35_ID(x) (((x) & 0x3f) << 23)
220#define DSI_PKT_SEQ_3_HI_PKT_35_SIZE(x) (((x) & 0x7) << 20)
221#define DSI_PKT_SEQ_3_HI_PKT_34_EN(x) (((x) & 0x1) << 19)
222#define DSI_PKT_SEQ_3_HI_PKT_34_ID(x) (((x) & 0x3f) << 13)
223#define DSI_PKT_SEQ_3_HI_PKT_34_SIZE(x) (((x) & 0x7) << 10)
224#define DSI_PKT_SEQ_3_HI_PKT_33_EN(x) (((x) & 0x1) << 9)
225#define DSI_PKT_SEQ_3_HI_PKT_33_ID(x) (((x) & 0x3f) << 3)
226#define DSI_PKT_SEQ_3_HI_PKT_33_SIZE(x) (((x) & 0x7) << 0)
227
228#define DSI_PKT_SEQ_4_LO 0x2b
229#define DSI_PKT_SEQ_4_LO_SEQ_4_FORCE_LP(x) (((x) & 0x1) << 30)
230#define DSI_PKT_SEQ_4_LO_PKT_42_EN(x) (((x) & 0x1) << 29)
231#define DSI_PKT_SEQ_4_LO_PKT_42_ID(x) (((x) & 0x3f) << 23)
232#define DSI_PKT_SEQ_4_LO_PKT_42_SIZE(x) (((x) & 0x7) << 20)
233#define DSI_PKT_SEQ_4_LO_PKT_41_EN(x) (((x) & 0x1) << 19)
234#define DSI_PKT_SEQ_4_LO_PKT_41_ID(x) (((x) & 0x3f) << 13)
235#define DSI_PKT_SEQ_4_LO_PKT_41_SIZE(x) (((x) & 0x7) << 10)
236#define DSI_PKT_SEQ_4_LO_PKT_40_EN(x) (((x) & 0x1) << 9)
237#define DSI_PKT_SEQ_4_LO_PKT_40_ID(x) (((x) & 0x3f) << 3)
238#define DSI_PKT_SEQ_4_LO_PKT_40_SIZE(x) (((x) & 0x7) << 0)
239
240#define DSI_PKT_SEQ_4_HI 0x2c
241#define DSI_PKT_SEQ_4_HI_PKT_45_EN(x) (((x) & 0x1) << 29)
242#define DSI_PKT_SEQ_4_HI_PKT_45_ID(x) (((x) & 0x3f) << 23)
243#define DSI_PKT_SEQ_4_HI_PKT_45_SIZE(x) (((x) & 0x7) << 20)
244#define DSI_PKT_SEQ_4_HI_PKT_44_EN(x) (((x) & 0x1) << 19)
245#define DSI_PKT_SEQ_4_HI_PKT_44_ID(x) (((x) & 0x3f) << 13)
246#define DSI_PKT_SEQ_4_HI_PKT_44_SIZE(x) (((x) & 0x7) << 10)
247#define DSI_PKT_SEQ_4_HI_PKT_43_EN(x) (((x) & 0x1) << 9)
248#define DSI_PKT_SEQ_4_HI_PKT_43_ID(x) (((x) & 0x3f) << 3)
249#define DSI_PKT_SEQ_4_HI_PKT_43_SIZE(x) (((x) & 0x7) << 0)
250
251#define DSI_PKT_SEQ_5_LO 0x2d
252#define DSI_PKT_SEQ_5_LO_SEQ_5_FORCE_LP(x) (((x) & 0x1) << 30)
253#define DSI_PKT_SEQ_5_LO_PKT_52_EN(x) (((x) & 0x1) << 29)
254#define DSI_PKT_SEQ_5_LO_PKT_52_ID(x) (((x) & 0x3f) << 23)
255#define DSI_PKT_SEQ_5_LO_PKT_52_SIZE(x) (((x) & 0x7) << 20)
256#define DSI_PKT_SEQ_5_LO_PKT_51_EN(x) (((x) & 0x1) << 19)
257#define DSI_PKT_SEQ_5_LO_PKT_51_ID(x) (((x) & 0x3f) << 13)
258#define DSI_PKT_SEQ_5_LO_PKT_51_SIZE(x) (((x) & 0x7) << 10)
259#define DSI_PKT_SEQ_5_LO_PKT_50_EN(x) (((x) & 0x1) << 9)
260#define DSI_PKT_SEQ_5_LO_PKT_50_ID(x) (((x) & 0x3f) << 3)
261#define DSI_PKT_SEQ_5_LO_PKT_50_SIZE(x) (((x) & 0x7) << 0)
262
263#define DSI_PKT_SEQ_5_HI 0x2e
264#define DSI_PKT_SEQ_5_HI_PKT_55_EN(x) (((x) & 0x1) << 29)
265#define DSI_PKT_SEQ_5_HI_PKT_55_ID(x) (((x) & 0x3f) << 23)
266#define DSI_PKT_SEQ_5_HI_PKT_55_SIZE(x) (((x) & 0x7) << 20)
267#define DSI_PKT_SEQ_5_HI_PKT_54_EN(x) (((x) & 0x1) << 19)
268#define DSI_PKT_SEQ_5_HI_PKT_54_ID(x) (((x) & 0x3f) << 13)
269#define DSI_PKT_SEQ_5_HI_PKT_54_SIZE(x) (((x) & 0x7) << 10)
270#define DSI_PKT_SEQ_5_HI_PKT_53_EN(x) (((x) & 0x1) << 9)
271#define DSI_PKT_SEQ_5_HI_PKT_53_ID(x) (((x) & 0x3f) << 3)
272#define DSI_PKT_SEQ_5_HI_PKT_53_SIZE(x) (((x) & 0x7) << 0)
273
274#define DSI_DCS_CMDS 0x33
275#define DSI_DCS_CMDS_LT5_DCS_CMD(x) (((x) & 0xff) << 8)
276#define DSI_DCS_CMDS_LT3_DCS_CMD(x) (((x) & 0xff) << 0)
277
278#define DSI_PKT_LEN_0_1 0x34
279#define DSI_PKT_LEN_0_1_LENGTH_1(x) (((x) & 0xffff) << 16)
280#define DSI_PKT_LEN_0_1_LENGTH_0(x) (((x) & 0xffff) << 0)
281
282#define DSI_PKT_LEN_2_3 0x35
283#define DSI_PKT_LEN_2_3_LENGTH_3(x) (((x) & 0xffff) << 16)
284#define DSI_PKT_LEN_2_3_LENGTH_2(x) (((x) & 0xffff) << 0)
285
286
287#define DSI_PKT_LEN_4_5 0x36
288#define DSI_PKT_LEN_4_5_LENGTH_5(x) (((x) & 0xffff) << 16)
289#define DSI_PKT_LEN_4_5_LENGTH_4(x) (((x) & 0xffff) << 0)
290
291#define DSI_PKT_LEN_6_7 0x37
292#define DSI_PKT_LEN_6_7_LENGTH_7(x) (((x) & 0xffff) << 16)
293#define DSI_PKT_LEN_6_7_LENGTH_6(x) (((x) & 0xffff) << 0)
294
295#define DSI_PHY_TIMING_0 0x3c
296#define DSI_PHY_TIMING_0_THSDEXIT(x) (((x) & 0xff) << 24)
297#define DSI_PHY_TIMING_0_THSTRAIL(x) (((x) & 0xff) << 16)
298#define DSI_PHY_TIMING_0_TDATZERO(x) (((x) & 0xff) << 8)
299#define DSI_PHY_TIMING_0_THSPREPR(x) (((x) & 0xff) << 0)
300
301#define DSI_PHY_TIMING_1 0x3d
302#define DSI_PHY_TIMING_1_TCLKTRAIL(x) (((x) & 0xff) << 24)
303#define DSI_PHY_TIMING_1_TCLKPOST(x) (((x) & 0xff) << 16)
304#define DSI_PHY_TIMING_1_TCLKZERO(x) (((x) & 0xff) << 8)
305#define DSI_PHY_TIMING_1_TTLPX(x) (((x) & 0xff) << 0)
306
307#define DSI_PHY_TIMING_2 0x3e
308#define DSI_PHY_TIMING_2_TCLKPREPARE(x) (((x) & 0xff) << 16)
309#define DSI_PHY_TIMING_2_TCLKPRE(x) (((x) & 0xff) << 8)
310#define DSI_PHY_TIMING_2_TWAKEUP(x) (((x) & 0xff) << 0)
311
312#define DSI_BTA_TIMING 0x3f
313#define DSI_BTA_TIMING_TTAGET(x) (((x) & 0xff) << 16)
314#define DSI_BTA_TIMING_TTASURE(x) (((x) & 0xff) << 8)
315#define DSI_BTA_TIMING_TTAGO(x) (((x) & 0xff) << 0)
316
317
318#define DSI_TIMEOUT_0 0x44
319#define DSI_TIMEOUT_0_LRXH_TO(x) (((x) & 0xffff) << 16)
320#define DSI_TIMEOUT_0_HTX_TO(x) (((x) & 0xffff) << 0)
321
322#define DSI_TIMEOUT_1 0x45
323#define DSI_TIMEOUT_1_PR_TO(x) (((x) & 0xffff) << 16)
324#define DSI_TIMEOUT_1_TA_TO(x) (((x) & 0xffff) << 0)
325
326#define DSI_TO_TALLY 0x46
327enum {
328 IN_RESET,
329 READY,
330};
331#define DSI_TO_TALLY_P_RESET_STATUS(x) (((x) & 0x1) << 24)
332#define DSI_TO_TALLY_TA_TALLY(x) (((x) & 0xff) << 16)
333#define DSI_TO_TALLY_LRXH_TALLY(x) (((x) & 0xff) << 8)
334#define DSI_TO_TALLY_HTX_TALLY(x) (((x) & 0xff) << 0)
335
336#define DSI_PAD_CONTROL 0x4b
337#define DSI_PAD_CONTROL_PAD_PULLDN_ENAB(x) (((x) & 0x1) << 28)
338#define DSI_PAD_CONTROL_PAD_SLEWUPADJ(x) (((x) & 0x7) << 24)
339#define DSI_PAD_CONTROL_PAD_SLEWDNADJ(x) (((x) & 0x7) << 20)
340#define DSI_PAD_CONTROL_PAD_PREEMP_EN(x) (((x) & 0x1) << 19)
341#define DSI_PAD_CONTROL_PAD_PDIO_CLK(x) (((x) & 0x1) << 18)
342#define DSI_PAD_CONTROL_PAD_PDIO(x) (((x) & 0x3) << 16)
343#define DSI_PAD_CONTROL_PAD_LPUPADJ(x) (((x) & 0x3) << 14)
344#define DSI_PAD_CONTROL_PAD_LPDNADJ(x) (((x) & 0x3) << 12)
345
346#define DSI_PAD_CONTROL_CD 0x4c
347#define DSI_PAD_CD_STATUS 0x4d
348#define DSI_VID_MODE_CONTROL 0x4e
349
350#endif
351
diff --git a/drivers/video/tegra/dc/edid.c b/drivers/video/tegra/dc/edid.c
new file mode 100644
index 00000000000..fbcf2cc8e37
--- /dev/null
+++ b/drivers/video/tegra/dc/edid.c
@@ -0,0 +1,619 @@
1/*
2 * drivers/video/tegra/dc/edid.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2010-2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20
21#include <linux/debugfs.h>
22#include <linux/fb.h>
23#include <linux/i2c.h>
24#include <linux/seq_file.h>
25#include <linux/vmalloc.h>
26
27#include "edid.h"
28
29struct tegra_edid_pvt {
30 struct kref refcnt;
31 struct tegra_edid_hdmi_eld eld;
32 bool support_stereo;
33 bool support_underscan;
34 /* Note: dc_edid must remain the last member */
35 struct tegra_dc_edid dc_edid;
36};
37
38struct tegra_edid {
39 struct i2c_client *client;
40 struct i2c_board_info info;
41 int bus;
42
43 struct tegra_edid_pvt *data;
44
45 struct mutex lock;
46};
47
48#if defined(DEBUG) || defined(CONFIG_DEBUG_FS)
49static int tegra_edid_show(struct seq_file *s, void *unused)
50{
51 struct tegra_edid *edid = s->private;
52 struct tegra_dc_edid *data;
53 u8 *buf;
54 int i;
55
56 data = tegra_edid_get_data(edid);
57 if (!data) {
58 seq_printf(s, "No EDID\n");
59 return 0;
60 }
61
62 buf = data->buf;
63
64 for (i = 0; i < data->len; i++) {
65 if (i % 16 == 0)
66 seq_printf(s, "edid[%03x] =", i);
67
68 seq_printf(s, " %02x", buf[i]);
69
70 if (i % 16 == 15)
71 seq_printf(s, "\n");
72 }
73
74 tegra_edid_put_data(data);
75
76 return 0;
77}
78#endif
79
80#ifdef CONFIG_DEBUG_FS
81static int tegra_edid_debug_open(struct inode *inode, struct file *file)
82{
83 return single_open(file, tegra_edid_show, inode->i_private);
84}
85
86static const struct file_operations tegra_edid_debug_fops = {
87 .open = tegra_edid_debug_open,
88 .read = seq_read,
89 .llseek = seq_lseek,
90 .release = single_release,
91};
92
93void tegra_edid_debug_add(struct tegra_edid *edid)
94{
95 char name[] = "edidX";
96
97 snprintf(name, sizeof(name), "edid%1d", edid->bus);
98 debugfs_create_file(name, S_IRUGO, NULL, edid, &tegra_edid_debug_fops);
99}
100#else
101void tegra_edid_debug_add(struct tegra_edid *edid)
102{
103}
104#endif
105
106#ifdef DEBUG
107static char tegra_edid_dump_buff[16 * 1024];
108
109static void tegra_edid_dump(struct tegra_edid *edid)
110{
111 struct seq_file s;
112 int i;
113 char c;
114
115 memset(&s, 0x0, sizeof(s));
116
117 s.buf = tegra_edid_dump_buff;
118 s.size = sizeof(tegra_edid_dump_buff);
119 s.private = edid;
120
121 tegra_edid_show(&s, NULL);
122
123 i = 0;
124 while (i < s.count ) {
125 if ((s.count - i) > 256) {
126 c = s.buf[i + 256];
127 s.buf[i + 256] = 0;
128 printk("%s", s.buf + i);
129 s.buf[i + 256] = c;
130 } else {
131 printk("%s", s.buf + i);
132 }
133 i += 256;
134 }
135}
136#else
137static void tegra_edid_dump(struct tegra_edid *edid)
138{
139}
140#endif
141
142int tegra_edid_read_block(struct tegra_edid *edid, int block, u8 *data)
143{
144 u8 block_buf[] = {block >> 1};
145 u8 cmd_buf[] = {(block & 0x1) * 128};
146 int status;
147 struct i2c_msg msg[] = {
148 {
149 .addr = 0x30,
150 .flags = 0,
151 .len = 1,
152 .buf = block_buf,
153 },
154 {
155 .addr = 0x50,
156 .flags = 0,
157 .len = 1,
158 .buf = cmd_buf,
159 },
160 {
161 .addr = 0x50,
162 .flags = I2C_M_RD,
163 .len = 128,
164 .buf = data,
165 }};
166 struct i2c_msg *m;
167 int msg_len;
168
169 if (block > 1) {
170 msg_len = 3;
171 m = msg;
172 } else {
173 msg_len = 2;
174 m = &msg[1];
175 }
176
177 status = i2c_transfer(edid->client->adapter, m, msg_len);
178
179 if (status < 0)
180 return status;
181
182 if (status != msg_len)
183 return -EIO;
184
185 return 0;
186}
187
188int tegra_edid_parse_ext_block(const u8 *raw, int idx,
189 struct tegra_edid_pvt *edid)
190{
191 const u8 *ptr;
192 u8 tmp;
193 u8 code;
194 int len;
195 int i;
196 bool basic_audio = false;
197
198 ptr = &raw[0];
199
200 /* If CEA 861 block get info for eld struct */
201 if (edid && ptr) {
202 if (*ptr <= 3)
203 edid->eld.eld_ver = 0x02;
204 edid->eld.cea_edid_ver = ptr[1];
205
206 /* check for basic audio support in CEA 861 block */
207 if(raw[3] & (1<<6)) {
208 /* For basic audio, set spk_alloc to Left+Right.
209 * If there is a Speaker Alloc block this will
210 * get over written with that value */
211 basic_audio = true;
212 }
213 }
214
215 if (raw[3] & 0x80)
216 edid->support_underscan = 1;
217 else
218 edid->support_underscan = 0;
219
220 ptr = &raw[4];
221
222 while (ptr < &raw[idx]) {
223 tmp = *ptr;
224 len = tmp & 0x1f;
225
226 /* HDMI Specification v1.4a, section 8.3.2:
227 * see Table 8-16 for HDMI VSDB format.
228 * data blocks have tags in top 3 bits:
229 * tag code 2: video data block
230 * tag code 3: vendor specific data block
231 */
232 code = (tmp >> 5) & 0x7;
233 switch (code) {
234 case 1:
235 {
236 edid->eld.sad_count = len;
237 edid->eld.conn_type = 0x00;
238 edid->eld.support_hdcp = 0x00;
239 for (i = 0; (i < len) && (i < ELD_MAX_SAD); i ++)
240 edid->eld.sad[i] = ptr[i + 1];
241 len++;
242 ptr += len; /* adding the header */
243 /* Got an audio data block so enable audio */
244 if(basic_audio == true)
245 edid->eld.spk_alloc = 1;
246 break;
247 }
248 /* case 2 is commented out for now */
249 case 3:
250 {
251 int j = 0;
252
253 if ((ptr[1] == 0x03) &&
254 (ptr[2] == 0x0c) &&
255 (ptr[3] == 0)) {
256 edid->eld.port_id[0] = ptr[4];
257 edid->eld.port_id[1] = ptr[5];
258 }
259 if ((len >= 8) &&
260 (ptr[1] == 0x03) &&
261 (ptr[2] == 0x0c) &&
262 (ptr[3] == 0)) {
263 j = 8;
264 tmp = ptr[j++];
265 /* HDMI_Video_present? */
266 if (tmp & 0x20) {
267 /* Latency_Fields_present? */
268 if (tmp & 0x80)
269 j += 2;
270 /* I_Latency_Fields_present? */
271 if (tmp & 0x40)
272 j += 2;
273 /* 3D_present? */
274 if (j <= len && (ptr[j] & 0x80))
275 edid->support_stereo = 1;
276 }
277 }
278 if ((len > 5) &&
279 (ptr[1] == 0x03) &&
280 (ptr[2] == 0x0c) &&
281 (ptr[3] == 0)) {
282
283 edid->eld.support_ai = (ptr[6] & 0x80);
284 }
285
286 if ((len > 9) &&
287 (ptr[1] == 0x03) &&
288 (ptr[2] == 0x0c) &&
289 (ptr[3] == 0)) {
290
291 edid->eld.aud_synch_delay = ptr[10];
292 }
293 len++;
294 ptr += len; /* adding the header */
295 break;
296 }
297 case 4:
298 {
299 edid->eld.spk_alloc = ptr[1];
300 len++;
301 ptr += len; /* adding the header */
302 break;
303 }
304 default:
305 len++; /* len does not include header */
306 ptr += len;
307 break;
308 }
309 }
310
311 return 0;
312}
313
314int tegra_edid_mode_support_stereo(struct fb_videomode *mode)
315{
316 if (!mode)
317 return 0;
318
319 if (mode->xres == 1280 &&
320 mode->yres == 720 &&
321 ((mode->refresh == 60) || (mode->refresh == 50)))
322 return 1;
323
324 /* Disabling 1080p stereo mode due to bug 869099. */
325 /* Must re-enable this to 1 once it is fixed. */
326 if (mode->xres == 1920 && mode->yres == 1080 && mode->refresh == 24)
327 return 0;
328
329 return 0;
330}
331
332static void data_release(struct kref *ref)
333{
334 struct tegra_edid_pvt *data =
335 container_of(ref, struct tegra_edid_pvt, refcnt);
336 vfree(data);
337}
338
339int tegra_edid_get_monspecs_test(struct tegra_edid *edid,
340 struct fb_monspecs *specs, unsigned char *edid_ptr)
341{
342 int i, j, ret;
343 int extension_blocks;
344 struct tegra_edid_pvt *new_data, *old_data;
345 u8 *data;
346
347 new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt));
348 if (!new_data)
349 return -ENOMEM;
350
351 kref_init(&new_data->refcnt);
352
353 new_data->support_stereo = 0;
354 new_data->support_underscan = 0;
355
356 data = new_data->dc_edid.buf;
357 memcpy(data, edid_ptr, 128);
358
359 memset(specs, 0x0, sizeof(struct fb_monspecs));
360 memset(&new_data->eld, 0x0, sizeof(new_data->eld));
361 fb_edid_to_monspecs(data, specs);
362 if (specs->modedb == NULL) {
363 ret = -EINVAL;
364 goto fail;
365 }
366
367 memcpy(new_data->eld.monitor_name, specs->monitor,
368 sizeof(specs->monitor));
369
370 new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1;
371 new_data->eld.product_id[0] = data[0x8];
372 new_data->eld.product_id[1] = data[0x9];
373 new_data->eld.manufacture_id[0] = data[0xA];
374 new_data->eld.manufacture_id[1] = data[0xB];
375
376 extension_blocks = data[0x7e];
377 for (i = 1; i <= extension_blocks; i++) {
378 memcpy(data+128, edid_ptr+128, 128);
379
380 if (data[i * 128] == 0x2) {
381 fb_edid_add_monspecs(data + i * 128, specs);
382
383 tegra_edid_parse_ext_block(data + i * 128,
384 data[i * 128 + 2], new_data);
385
386 if (new_data->support_stereo) {
387 for (j = 0; j < specs->modedb_len; j++) {
388 if (tegra_edid_mode_support_stereo(
389 &specs->modedb[j]))
390 specs->modedb[j].vmode |=
391#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
392 FB_VMODE_STEREO_FRAME_PACK;
393#else
394 FB_VMODE_STEREO_LEFT_RIGHT;
395#endif
396 }
397 }
398 }
399 }
400
401 new_data->dc_edid.len = i * 128;
402
403 mutex_lock(&edid->lock);
404 old_data = edid->data;
405 edid->data = new_data;
406 mutex_unlock(&edid->lock);
407
408 if (old_data)
409 kref_put(&old_data->refcnt, data_release);
410
411 tegra_edid_dump(edid);
412 return 0;
413fail:
414 vfree(new_data);
415 return ret;
416}
417
418int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs)
419{
420 int i;
421 int j;
422 int ret;
423 int extension_blocks;
424 struct tegra_edid_pvt *new_data, *old_data;
425 u8 *data;
426
427 new_data = vmalloc(SZ_32K + sizeof(struct tegra_edid_pvt));
428 if (!new_data)
429 return -ENOMEM;
430
431 kref_init(&new_data->refcnt);
432
433 new_data->support_stereo = 0;
434
435 data = new_data->dc_edid.buf;
436
437 ret = tegra_edid_read_block(edid, 0, data);
438 if (ret)
439 goto fail;
440
441 memset(specs, 0x0, sizeof(struct fb_monspecs));
442 memset(&new_data->eld, 0x0, sizeof(new_data->eld));
443 fb_edid_to_monspecs(data, specs);
444 if (specs->modedb == NULL) {
445 ret = -EINVAL;
446 goto fail;
447 }
448 memcpy(new_data->eld.monitor_name, specs->monitor, sizeof(specs->monitor));
449 new_data->eld.mnl = strlen(new_data->eld.monitor_name) + 1;
450 new_data->eld.product_id[0] = data[0x8];
451 new_data->eld.product_id[1] = data[0x9];
452 new_data->eld.manufacture_id[0] = data[0xA];
453 new_data->eld.manufacture_id[1] = data[0xB];
454
455 extension_blocks = data[0x7e];
456
457 for (i = 1; i <= extension_blocks; i++) {
458 ret = tegra_edid_read_block(edid, i, data + i * 128);
459 if (ret < 0)
460 break;
461
462 if (data[i * 128] == 0x2) {
463 fb_edid_add_monspecs(data + i * 128, specs);
464
465 tegra_edid_parse_ext_block(data + i * 128,
466 data[i * 128 + 2], new_data);
467
468 if (new_data->support_stereo) {
469 for (j = 0; j < specs->modedb_len; j++) {
470 if (tegra_edid_mode_support_stereo(
471 &specs->modedb[j]))
472 specs->modedb[j].vmode |=
473#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
474 FB_VMODE_STEREO_FRAME_PACK;
475#else
476 FB_VMODE_STEREO_LEFT_RIGHT;
477#endif
478 }
479 }
480 }
481 }
482
483 new_data->dc_edid.len = i * 128;
484
485 mutex_lock(&edid->lock);
486 old_data = edid->data;
487 edid->data = new_data;
488 mutex_unlock(&edid->lock);
489
490 if (old_data)
491 kref_put(&old_data->refcnt, data_release);
492
493 tegra_edid_dump(edid);
494 return 0;
495
496fail:
497 vfree(new_data);
498 return ret;
499}
500
501int tegra_edid_underscan_supported(struct tegra_edid *edid)
502{
503 if ((!edid) || (!edid->data))
504 return 0;
505
506 return edid->data->support_underscan;
507}
508
509int tegra_edid_get_eld(struct tegra_edid *edid, struct tegra_edid_hdmi_eld *elddata)
510{
511 if (!elddata || !edid->data)
512 return -EFAULT;
513
514 memcpy(elddata,&edid->data->eld,sizeof(struct tegra_edid_hdmi_eld));
515
516 return 0;
517}
518
519struct tegra_edid *tegra_edid_create(int bus)
520{
521 struct tegra_edid *edid;
522 struct i2c_adapter *adapter;
523 int err;
524
525 edid = kzalloc(sizeof(struct tegra_edid), GFP_KERNEL);
526 if (!edid)
527 return ERR_PTR(-ENOMEM);
528
529 mutex_init(&edid->lock);
530 strlcpy(edid->info.type, "tegra_edid", sizeof(edid->info.type));
531 edid->bus = bus;
532 edid->info.addr = 0x50;
533 edid->info.platform_data = edid;
534
535 adapter = i2c_get_adapter(bus);
536 if (!adapter) {
537 pr_err("can't get adpater for bus %d\n", bus);
538 err = -EBUSY;
539 goto free_edid;
540 }
541
542 edid->client = i2c_new_device(adapter, &edid->info);
543 i2c_put_adapter(adapter);
544
545 if (!edid->client) {
546 pr_err("can't create new device\n");
547 err = -EBUSY;
548 goto free_edid;
549 }
550
551 tegra_edid_debug_add(edid);
552
553 return edid;
554
555free_edid:
556 kfree(edid);
557
558 return ERR_PTR(err);
559}
560
561void tegra_edid_destroy(struct tegra_edid *edid)
562{
563 i2c_release_client(edid->client);
564 if (edid->data)
565 kref_put(&edid->data->refcnt, data_release);
566 kfree(edid);
567}
568
569struct tegra_dc_edid *tegra_edid_get_data(struct tegra_edid *edid)
570{
571 struct tegra_edid_pvt *data;
572
573 mutex_lock(&edid->lock);
574 data = edid->data;
575 if (data)
576 kref_get(&data->refcnt);
577 mutex_unlock(&edid->lock);
578
579 return data ? &data->dc_edid : NULL;
580}
581
582void tegra_edid_put_data(struct tegra_dc_edid *data)
583{
584 struct tegra_edid_pvt *pvt;
585
586 if (!data)
587 return;
588
589 pvt = container_of(data, struct tegra_edid_pvt, dc_edid);
590
591 kref_put(&pvt->refcnt, data_release);
592}
593
594static const struct i2c_device_id tegra_edid_id[] = {
595 { "tegra_edid", 0 },
596 { }
597};
598
599MODULE_DEVICE_TABLE(i2c, tegra_edid_id);
600
601static struct i2c_driver tegra_edid_driver = {
602 .id_table = tegra_edid_id,
603 .driver = {
604 .name = "tegra_edid",
605 },
606};
607
608static int __init tegra_edid_init(void)
609{
610 return i2c_add_driver(&tegra_edid_driver);
611}
612
613static void __exit tegra_edid_exit(void)
614{
615 i2c_del_driver(&tegra_edid_driver);
616}
617
618module_init(tegra_edid_init);
619module_exit(tegra_edid_exit);
diff --git a/drivers/video/tegra/dc/edid.h b/drivers/video/tegra/dc/edid.h
new file mode 100644
index 00000000000..77db36f4adb
--- /dev/null
+++ b/drivers/video/tegra/dc/edid.h
@@ -0,0 +1,62 @@
1/*
2 * drivers/video/tegra/dc/edid.h
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#ifndef __DRIVERS_VIDEO_TEGRA_DC_EDID_H
19#define __DRIVERS_VIDEO_TEGRA_DC_EDID_H
20
21#include <linux/i2c.h>
22#include <linux/wait.h>
23#include <mach/dc.h>
24
25#define ELD_MAX_MNL 16
26#define ELD_MAX_SAD 16
27struct tegra_edid;
28
29/*
30 * ELD: EDID Like Data
31 */
32struct tegra_edid_hdmi_eld {
33 u8 baseline_len;
34 u8 eld_ver;
35 u8 cea_edid_ver;
36 char monitor_name[ELD_MAX_MNL + 1];
37 u8 mnl;
38 u8 manufacture_id[2];
39 u8 product_id[2];
40 u8 port_id[8];
41 u8 support_hdcp;
42 u8 support_ai;
43 u8 conn_type;
44 u8 aud_synch_delay;
45 u8 spk_alloc;
46 u8 sad_count;
47 u8 sad[ELD_MAX_SAD];
48};
49
50struct tegra_edid *tegra_edid_create(int bus);
51void tegra_edid_destroy(struct tegra_edid *edid);
52
53int tegra_edid_get_monspecs_test(struct tegra_edid *edid,
54 struct fb_monspecs *specs, u8 *edid_ptr);
55int tegra_edid_get_monspecs(struct tegra_edid *edid, struct fb_monspecs *specs);
56int tegra_edid_get_eld(struct tegra_edid *edid, struct tegra_edid_hdmi_eld *elddata);
57
58struct tegra_dc_edid *tegra_edid_get_data(struct tegra_edid *edid);
59void tegra_edid_put_data(struct tegra_dc_edid *data);
60
61int tegra_edid_underscan_supported(struct tegra_edid *edid);
62#endif
diff --git a/drivers/video/tegra/dc/ext/Makefile b/drivers/video/tegra/dc/ext/Makefile
new file mode 100644
index 00000000000..19860ab5db1
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/Makefile
@@ -0,0 +1,5 @@
1obj-y += dev.o
2obj-y += util.o
3obj-y += cursor.o
4obj-y += events.o
5obj-y += control.o
diff --git a/drivers/video/tegra/dc/ext/control.c b/drivers/video/tegra/dc/ext/control.c
new file mode 100644
index 00000000000..9caf3e11c16
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/control.c
@@ -0,0 +1,279 @@
1/*
2 * drivers/video/tegra/dc/ext/control.c
3 *
4 * Copyright (C) 2011, NVIDIA Corporation
5 *
6 * Author: Robert Morell <rmorell@nvidia.com>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 */
18
19#include <linux/device.h>
20#include <linux/err.h>
21#include <linux/file.h>
22#include <linux/fs.h>
23#include <linux/slab.h>
24#include <linux/module.h>
25#include <linux/uaccess.h>
26
27#include "tegra_dc_ext_priv.h"
28
29static struct tegra_dc_ext_control g_control;
30
31int tegra_dc_ext_process_hotplug(int output)
32{
33 return tegra_dc_ext_queue_hotplug(&g_control, output);
34}
35
36static int
37get_output_properties(struct tegra_dc_ext_control_output_properties *properties)
38{
39 struct tegra_dc *dc;
40
41 /* TODO: this should be more dynamic */
42 if (properties->handle > 2)
43 return -EINVAL;
44
45 switch (properties->handle) {
46 case 0:
47 properties->type = TEGRA_DC_EXT_LVDS;
48 break;
49 case 1:
50 properties->type = TEGRA_DC_EXT_HDMI;
51 break;
52 default:
53 return -EINVAL;
54 }
55
56 properties->associated_head = properties->handle;
57 properties->head_mask = (1 << properties->associated_head);
58
59 dc = tegra_dc_get_dc(properties->associated_head);
60 properties->connected = tegra_dc_get_connected(dc);
61
62 return 0;
63}
64
65static int get_output_edid(struct tegra_dc_ext_control_output_edid *edid)
66{
67 struct tegra_dc *dc;
68 size_t user_size = edid->size;
69 struct tegra_dc_edid *dc_edid = NULL;
70 int ret;
71
72 /* TODO: this should be more dynamic */
73 if (edid->handle > 2)
74 return -EINVAL;
75
76 dc = tegra_dc_get_dc(edid->handle);
77
78 dc_edid = tegra_dc_get_edid(dc);
79 if (IS_ERR(dc_edid))
80 return PTR_ERR(dc_edid);
81
82 if (!dc_edid) {
83 edid->size = 0;
84 } else {
85 edid->size = dc_edid->len;
86
87 if (user_size < edid->size) {
88 ret = -EFBIG;
89 goto done;
90 }
91
92 if (copy_to_user(edid->data, dc_edid->buf, edid->size)) {
93 ret = -EFAULT;
94 goto done;
95 }
96
97 }
98
99done:
100 if (dc_edid)
101 tegra_dc_put_edid(dc_edid);
102
103 return ret;
104}
105
106static int set_event_mask(struct tegra_dc_ext_control_user *user, u32 mask)
107{
108 struct list_head *list, *tmp;
109
110 if (mask & ~TEGRA_DC_EXT_EVENT_MASK_ALL)
111 return -EINVAL;
112
113 mutex_lock(&user->lock);
114
115 user->event_mask = mask;
116
117 list_for_each_safe(list, tmp, &user->event_list) {
118 struct tegra_dc_ext_event_list *ev_list;
119 ev_list = list_entry(list, struct tegra_dc_ext_event_list,
120 list);
121 if (!(mask & ev_list->event.type)) {
122 list_del(list);
123 kfree(ev_list);
124 }
125 }
126 mutex_unlock(&user->lock);
127
128 return 0;
129}
130
131static int get_capabilities(struct tegra_dc_ext_control_capabilities *caps)
132{
133 caps->caps = TEGRA_DC_EXT_CAPABILITIES;
134 return 0;
135}
136
137static long tegra_dc_ext_control_ioctl(struct file *filp, unsigned int cmd,
138 unsigned long arg)
139{
140 void __user *user_arg = (void __user *)arg;
141 struct tegra_dc_ext_control_user *user = filp->private_data;
142
143 switch (cmd) {
144 case TEGRA_DC_EXT_CONTROL_GET_NUM_OUTPUTS:
145 {
146 u32 num = tegra_dc_ext_get_num_outputs();
147
148 if (copy_to_user(user_arg, &num, sizeof(num)))
149 return -EFAULT;
150
151 return 0;
152 }
153 case TEGRA_DC_EXT_CONTROL_GET_OUTPUT_PROPERTIES:
154 {
155 struct tegra_dc_ext_control_output_properties args;
156 int ret;
157
158 if (copy_from_user(&args, user_arg, sizeof(args)))
159 return -EFAULT;
160
161 ret = get_output_properties(&args);
162
163 if (copy_to_user(user_arg, &args, sizeof(args)))
164 return -EFAULT;
165
166 return ret;
167 }
168 case TEGRA_DC_EXT_CONTROL_GET_OUTPUT_EDID:
169 {
170 struct tegra_dc_ext_control_output_edid args;
171 int ret;
172
173 if (copy_from_user(&args, user_arg, sizeof(args)))
174 return -EFAULT;
175
176 ret = get_output_edid(&args);
177
178 if (copy_to_user(user_arg, &args, sizeof(args)))
179 return -EFAULT;
180
181 return ret;
182 }
183 case TEGRA_DC_EXT_CONTROL_SET_EVENT_MASK:
184 return set_event_mask(user, (u32) arg);
185 case TEGRA_DC_EXT_CONTROL_GET_CAPABILITIES:
186 {
187 struct tegra_dc_ext_control_capabilities args;
188 int ret;
189
190 ret = get_capabilities(&args);
191
192 if (copy_to_user(user_arg, &args, sizeof(args)))
193 return -EFAULT;
194
195 return ret;
196 }
197 default:
198 return -EINVAL;
199 }
200}
201
202static int tegra_dc_ext_control_open(struct inode *inode, struct file *filp)
203{
204 struct tegra_dc_ext_control_user *user;
205 struct tegra_dc_ext_control *control;
206
207 user = kzalloc(sizeof(*user), GFP_KERNEL);
208 if (!user)
209 return -ENOMEM;
210
211 control = container_of(inode->i_cdev, struct tegra_dc_ext_control,
212 cdev);
213 user->control = control;;
214
215 INIT_LIST_HEAD(&user->event_list);
216 mutex_init(&user->lock);
217
218 filp->private_data = user;
219
220 mutex_lock(&control->lock);
221 list_add(&user->list, &control->users);
222 mutex_unlock(&control->lock);
223
224 return 0;
225}
226
227static int tegra_dc_ext_control_release(struct inode *inode, struct file *filp)
228{
229 struct tegra_dc_ext_control_user *user = filp->private_data;
230 struct tegra_dc_ext_control *control = user->control;
231
232 /* This will free any pending events for this user */
233 set_event_mask(user, 0);
234
235 mutex_lock(&control->lock);
236 list_del(&user->list);
237 mutex_unlock(&control->lock);
238
239 kfree(user);
240
241 return 0;
242}
243
244static const struct file_operations tegra_dc_ext_event_devops = {
245 .owner = THIS_MODULE,
246 .open = tegra_dc_ext_control_open,
247 .release = tegra_dc_ext_control_release,
248 .read = tegra_dc_ext_event_read,
249 .poll = tegra_dc_ext_event_poll,
250 .unlocked_ioctl = tegra_dc_ext_control_ioctl,
251};
252
253int tegra_dc_ext_control_init(void)
254{
255 struct tegra_dc_ext_control *control = &g_control;
256 int ret;
257
258 cdev_init(&control->cdev, &tegra_dc_ext_event_devops);
259 control->cdev.owner = THIS_MODULE;
260 ret = cdev_add(&control->cdev, tegra_dc_ext_devno, 1);
261 if (ret)
262 return ret;
263
264 control->dev = device_create(tegra_dc_ext_class,
265 NULL,
266 tegra_dc_ext_devno,
267 NULL,
268 "tegra_dc_ctrl");
269 if (IS_ERR(control->dev)) {
270 ret = PTR_ERR(control->dev);
271 cdev_del(&control->cdev);
272 }
273
274 mutex_init(&control->lock);
275
276 INIT_LIST_HEAD(&control->users);
277
278 return ret;
279}
diff --git a/drivers/video/tegra/dc/ext/cursor.c b/drivers/video/tegra/dc/ext/cursor.c
new file mode 100644
index 00000000000..d8fa5fd8e6d
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/cursor.c
@@ -0,0 +1,203 @@
1/*
2 * drivers/video/tegra/dc/ext/cursor.c
3 *
4 * Copyright (C) 2011, NVIDIA Corporation
5 *
6 * Author: Robert Morell <rmorell@nvidia.com>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 */
18
19#include <video/tegra_dc_ext.h>
20
21#include "tegra_dc_ext_priv.h"
22
23/* ugh */
24#include "../dc_priv.h"
25#include "../dc_reg.h"
26
27int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user)
28{
29 struct tegra_dc_ext *ext = user->ext;
30 int ret = 0;
31
32 mutex_lock(&ext->cursor.lock);
33
34 if (!ext->cursor.user)
35 ext->cursor.user = user;
36 else if (ext->cursor.user != user)
37 ret = -EBUSY;
38
39 mutex_unlock(&ext->cursor.lock);
40
41 return ret;
42}
43
44int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user)
45{
46 struct tegra_dc_ext *ext = user->ext;
47 int ret = 0;
48
49 mutex_lock(&ext->cursor.lock);
50
51 if (ext->cursor.user == user)
52 ext->cursor.user = 0;
53 else
54 ret = -EACCES;
55
56 mutex_unlock(&ext->cursor.lock);
57
58 return ret;
59}
60
61static void set_cursor_image_hw(struct tegra_dc *dc,
62 struct tegra_dc_ext_cursor_image *args,
63 dma_addr_t phys_addr)
64{
65 tegra_dc_writel(dc,
66 CURSOR_COLOR(args->foreground.r,
67 args->foreground.g,
68 args->foreground.b),
69 DC_DISP_CURSOR_FOREGROUND);
70 tegra_dc_writel(dc,
71 CURSOR_COLOR(args->background.r,
72 args->background.g,
73 args->background.b),
74 DC_DISP_CURSOR_BACKGROUND);
75
76 BUG_ON(phys_addr & ~CURSOR_START_ADDR_MASK);
77
78 tegra_dc_writel(dc,
79 CURSOR_START_ADDR(((unsigned long) phys_addr)) |
80 ((args->flags & TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64) ?
81 CURSOR_SIZE_64 : 0),
82 DC_DISP_CURSOR_START_ADDR);
83}
84
85int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
86 struct tegra_dc_ext_cursor_image *args)
87{
88 struct tegra_dc_ext *ext = user->ext;
89 struct tegra_dc *dc = ext->dc;
90 struct nvmap_handle_ref *handle, *old_handle;
91 dma_addr_t phys_addr;
92 u32 size;
93 int ret;
94
95 if (!user->nvmap)
96 return -EFAULT;
97
98 size = args->flags & (TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 |
99 TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64);
100
101 if (size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_32x32 &&
102 size != TEGRA_DC_EXT_CURSOR_IMAGE_FLAGS_SIZE_64x64)
103 return -EINVAL;
104
105 mutex_lock(&ext->cursor.lock);
106
107 if (ext->cursor.user != user) {
108 ret = -EACCES;
109 goto unlock;
110 }
111
112 if (!ext->enabled) {
113 ret = -ENXIO;
114 goto unlock;
115 }
116
117 old_handle = ext->cursor.cur_handle;
118
119 ret = tegra_dc_ext_pin_window(user, args->buff_id, &handle, &phys_addr);
120 if (ret)
121 goto unlock;
122
123 ext->cursor.cur_handle = handle;
124
125 mutex_lock(&dc->lock);
126
127 set_cursor_image_hw(dc, args, phys_addr);
128
129 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
130 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
131
132 /* XXX sync here? */
133
134 mutex_unlock(&dc->lock);
135
136 mutex_unlock(&ext->cursor.lock);
137
138 if (old_handle) {
139 nvmap_unpin(ext->nvmap, old_handle);
140 nvmap_free(ext->nvmap, old_handle);
141 }
142
143 return 0;
144
145unlock:
146 mutex_unlock(&ext->cursor.lock);
147
148 return ret;
149}
150
151int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
152 struct tegra_dc_ext_cursor *args)
153{
154 struct tegra_dc_ext *ext = user->ext;
155 struct tegra_dc *dc = ext->dc;
156 u32 win_options;
157 bool enable;
158 int ret;
159
160 mutex_lock(&ext->cursor.lock);
161
162 if (ext->cursor.user != user) {
163 ret = -EACCES;
164 goto unlock;
165 }
166
167 if (!ext->enabled) {
168 ret = -ENXIO;
169 goto unlock;
170 }
171
172 enable = !!(args->flags & TEGRA_DC_EXT_CURSOR_FLAGS_VISIBLE);
173
174 mutex_lock(&dc->lock);
175
176 win_options = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
177 if (!!(win_options & CURSOR_ENABLE) != enable) {
178 win_options &= ~CURSOR_ENABLE;
179 if (enable)
180 win_options |= CURSOR_ENABLE;
181 tegra_dc_writel(dc, win_options, DC_DISP_DISP_WIN_OPTIONS);
182 }
183
184 tegra_dc_writel(dc, CURSOR_POSITION(args->x, args->y),
185 DC_DISP_CURSOR_POSITION);
186
187 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
188 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
189
190 /* TODO: need to sync here? hopefully can avoid this, but need to
191 * figure out interaction w/ rest of GENERAL_ACT_REQ */
192
193 mutex_unlock(&dc->lock);
194
195 mutex_unlock(&ext->cursor.lock);
196
197 return 0;
198
199unlock:
200 mutex_unlock(&ext->cursor.lock);
201
202 return ret;
203}
diff --git a/drivers/video/tegra/dc/ext/dev.c b/drivers/video/tegra/dc/ext/dev.c
new file mode 100644
index 00000000000..04553e77839
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/dev.c
@@ -0,0 +1,975 @@
1/*
2 * drivers/video/tegra/dc/dev.c
3 *
4 * Copyright (C) 2011-2012, NVIDIA Corporation
5 *
6 * Author: Robert Morell <rmorell@nvidia.com>
7 * Some code based on fbdev extensions written by:
8 * Erik Gilling <konkers@android.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * more details.
19 */
20
21#include <linux/file.h>
22#include <linux/fs.h>
23#include <linux/uaccess.h>
24#include <linux/slab.h>
25#include <linux/workqueue.h>
26
27#include <video/tegra_dc_ext.h>
28
29#include <mach/dc.h>
30#include <mach/nvmap.h>
31#include <mach/tegra_dc_ext.h>
32
33/* XXX ew */
34#include "../dc_priv.h"
35/* XXX ew 2 */
36#include "../../host/dev.h"
37/* XXX ew 3 */
38#include "../../nvmap/nvmap.h"
39#include "tegra_dc_ext_priv.h"
40
41int tegra_dc_ext_devno;
42struct class *tegra_dc_ext_class;
43static int head_count;
44
45struct tegra_dc_ext_flip_win {
46 struct tegra_dc_ext_flip_windowattr attr;
47 struct nvmap_handle_ref *handle[TEGRA_DC_NUM_PLANES];
48 dma_addr_t phys_addr;
49 dma_addr_t phys_addr_u;
50 dma_addr_t phys_addr_v;
51 u32 syncpt_max;
52};
53
54struct tegra_dc_ext_flip_data {
55 struct tegra_dc_ext *ext;
56 struct work_struct work;
57 struct tegra_dc_ext_flip_win win[DC_N_WINDOWS];
58};
59
60int tegra_dc_ext_get_num_outputs(void)
61{
62 /* TODO: decouple output count from head count */
63 return head_count;
64}
65
66static int tegra_dc_ext_set_nvmap_fd(struct tegra_dc_ext_user *user,
67 int fd)
68{
69 struct nvmap_client *nvmap = NULL;
70
71 if (fd >= 0) {
72 nvmap = nvmap_client_get_file(fd);
73 if (IS_ERR(nvmap))
74 return PTR_ERR(nvmap);
75 }
76
77 if (user->nvmap)
78 nvmap_client_put(user->nvmap);
79
80 user->nvmap = nvmap;
81
82 return 0;
83}
84
85static int tegra_dc_ext_get_window(struct tegra_dc_ext_user *user,
86 unsigned int n)
87{
88 struct tegra_dc_ext *ext = user->ext;
89 struct tegra_dc_ext_win *win;
90 int ret = 0;
91
92 if (n >= DC_N_WINDOWS)
93 return -EINVAL;
94
95 win = &ext->win[n];
96
97 mutex_lock(&win->lock);
98
99 if (!win->user)
100 win->user = user;
101 else if (win->user != user)
102 ret = -EBUSY;
103
104 mutex_unlock(&win->lock);
105
106 return ret;
107}
108
109static int tegra_dc_ext_put_window(struct tegra_dc_ext_user *user,
110 unsigned int n)
111{
112 struct tegra_dc_ext *ext = user->ext;
113 struct tegra_dc_ext_win *win;
114 int ret = 0;
115
116 if (n >= DC_N_WINDOWS)
117 return -EINVAL;
118
119 win = &ext->win[n];
120
121 mutex_lock(&win->lock);
122
123 if (win->user == user) {
124 flush_workqueue(win->flip_wq);
125 win->user = 0;
126 } else {
127 ret = -EACCES;
128 }
129
130 mutex_unlock(&win->lock);
131
132 return ret;
133}
134
135static void set_enable(struct tegra_dc_ext *ext, bool en)
136{
137 int i;
138
139 /*
140 * Take all locks to make sure any flip requests or cursor moves are
141 * out of their critical sections
142 */
143 for (i = 0; i < ext->dc->n_windows; i++)
144 mutex_lock(&ext->win[i].lock);
145 mutex_lock(&ext->cursor.lock);
146
147 ext->enabled = en;
148
149 mutex_unlock(&ext->cursor.lock);
150 for (i = ext->dc->n_windows - 1; i >= 0 ; i--)
151 mutex_unlock(&ext->win[i].lock);
152}
153
154void tegra_dc_ext_enable(struct tegra_dc_ext *ext)
155{
156 set_enable(ext, true);
157}
158
159void tegra_dc_ext_disable(struct tegra_dc_ext *ext)
160{
161 int i;
162 set_enable(ext, false);
163
164 /*
165 * Flush the flip queue -- note that this must be called with dc->lock
166 * unlocked or else it will hang.
167 */
168 for (i = 0; i < ext->dc->n_windows; i++) {
169 struct tegra_dc_ext_win *win = &ext->win[i];
170
171 flush_workqueue(win->flip_wq);
172 }
173}
174
175static int tegra_dc_ext_set_windowattr(struct tegra_dc_ext *ext,
176 struct tegra_dc_win *win,
177 const struct tegra_dc_ext_flip_win *flip_win)
178{
179 struct tegra_dc_ext_win *ext_win = &ext->win[win->idx];
180
181 if (flip_win->handle[TEGRA_DC_Y] == NULL) {
182 win->flags = 0;
183 memset(ext_win->cur_handle, 0, sizeof(ext_win->cur_handle));
184 return 0;
185 }
186
187 win->flags = TEGRA_WIN_FLAG_ENABLED;
188 if (flip_win->attr.blend == TEGRA_DC_EXT_BLEND_PREMULT)
189 win->flags |= TEGRA_WIN_FLAG_BLEND_PREMULT;
190 else if (flip_win->attr.blend == TEGRA_DC_EXT_BLEND_COVERAGE)
191 win->flags |= TEGRA_WIN_FLAG_BLEND_COVERAGE;
192 if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_TILED)
193 win->flags |= TEGRA_WIN_FLAG_TILED;
194 if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_H)
195 win->flags |= TEGRA_WIN_FLAG_INVERT_H;
196 if (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_INVERT_V)
197 win->flags |= TEGRA_WIN_FLAG_INVERT_V;
198 win->fmt = flip_win->attr.pixformat;
199 win->x.full = flip_win->attr.x;
200 win->y.full = flip_win->attr.y;
201 win->w.full = flip_win->attr.w;
202 win->h.full = flip_win->attr.h;
203 /* XXX verify that this doesn't go outside display's active region */
204 win->out_x = flip_win->attr.out_x;
205 win->out_y = flip_win->attr.out_y;
206 win->out_w = flip_win->attr.out_w;
207 win->out_h = flip_win->attr.out_h;
208 win->z = flip_win->attr.z;
209 memcpy(ext_win->cur_handle, flip_win->handle,
210 sizeof(ext_win->cur_handle));
211
212 /* XXX verify that this won't read outside of the surface */
213 win->phys_addr = flip_win->phys_addr + flip_win->attr.offset;
214
215 win->phys_addr_u = flip_win->handle[TEGRA_DC_U] ?
216 flip_win->phys_addr_u : flip_win->phys_addr;
217 win->phys_addr_u += flip_win->attr.offset_u;
218
219 win->phys_addr_v = flip_win->handle[TEGRA_DC_V] ?
220 flip_win->phys_addr_v : flip_win->phys_addr;
221 win->phys_addr_v += flip_win->attr.offset_v;
222
223 win->stride = flip_win->attr.stride;
224 win->stride_uv = flip_win->attr.stride_uv;
225
226 if ((s32)flip_win->attr.pre_syncpt_id >= 0) {
227 nvhost_syncpt_wait_timeout(
228 &nvhost_get_host(ext->dc->ndev)->syncpt,
229 flip_win->attr.pre_syncpt_id,
230 flip_win->attr.pre_syncpt_val,
231 msecs_to_jiffies(500), NULL);
232 }
233
234
235 return 0;
236}
237
238static void tegra_dc_ext_flip_worker(struct work_struct *work)
239{
240 struct tegra_dc_ext_flip_data *data =
241 container_of(work, struct tegra_dc_ext_flip_data, work);
242 struct tegra_dc_ext *ext = data->ext;
243 struct tegra_dc_win *wins[DC_N_WINDOWS];
244 struct nvmap_handle_ref *unpin_handles[DC_N_WINDOWS *
245 TEGRA_DC_NUM_PLANES];
246 struct nvmap_handle_ref *old_handle;
247 int i, nr_unpin = 0, nr_win = 0;
248 bool skip_flip = false;
249
250 for (i = 0; i < DC_N_WINDOWS; i++) {
251 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
252 int index = flip_win->attr.index;
253 struct tegra_dc_win *win;
254 struct tegra_dc_ext_win *ext_win;
255
256 if (index < 0)
257 continue;
258
259 win = tegra_dc_get_window(ext->dc, index);
260 ext_win = &ext->win[index];
261
262 if (!(atomic_dec_and_test(&ext_win->nr_pending_flips)) &&
263 (flip_win->attr.flags & TEGRA_DC_EXT_FLIP_FLAG_CURSOR))
264 skip_flip = true;
265
266 if (win->flags & TEGRA_WIN_FLAG_ENABLED) {
267 int j;
268 for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
269 if (skip_flip)
270 old_handle = flip_win->handle[j];
271 else
272 old_handle = ext_win->cur_handle[j];
273
274 if (!old_handle)
275 continue;
276
277 unpin_handles[nr_unpin++] = old_handle;
278 }
279 }
280
281 if (!skip_flip)
282 tegra_dc_ext_set_windowattr(ext, win, &data->win[i]);
283
284 wins[nr_win++] = win;
285 }
286
287 if (!skip_flip) {
288 tegra_dc_update_windows(wins, nr_win);
289 /* TODO: implement swapinterval here */
290 tegra_dc_sync_windows(wins, nr_win);
291 }
292
293 for (i = 0; i < DC_N_WINDOWS; i++) {
294 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
295 int index = flip_win->attr.index;
296
297 if (index < 0)
298 continue;
299
300 tegra_dc_incr_syncpt_min(ext->dc, index,
301 flip_win->syncpt_max);
302 }
303
304 /* unpin and deref previous front buffers */
305 for (i = 0; i < nr_unpin; i++) {
306 nvmap_unpin(ext->nvmap, unpin_handles[i]);
307 nvmap_free(ext->nvmap, unpin_handles[i]);
308 }
309
310 kfree(data);
311}
312
313static int lock_windows_for_flip(struct tegra_dc_ext_user *user,
314 struct tegra_dc_ext_flip *args)
315{
316 struct tegra_dc_ext *ext = user->ext;
317 u8 idx_mask = 0;
318 int i;
319
320 for (i = 0; i < DC_N_WINDOWS; i++) {
321 int index = args->win[i].index;
322
323 if (index < 0)
324 continue;
325
326 idx_mask |= BIT(index);
327 }
328
329 for (i = 0; i < DC_N_WINDOWS; i++) {
330 struct tegra_dc_ext_win *win;
331
332 if (!(idx_mask & BIT(i)))
333 continue;
334
335 win = &ext->win[i];
336
337 mutex_lock(&win->lock);
338
339 if (win->user != user)
340 goto fail_unlock;
341 }
342
343 return 0;
344
345fail_unlock:
346 do {
347 if (!(idx_mask & BIT(i)))
348 continue;
349
350 mutex_unlock(&ext->win[i].lock);
351 } while (i--);
352
353 return -EACCES;
354}
355
356static void unlock_windows_for_flip(struct tegra_dc_ext_user *user,
357 struct tegra_dc_ext_flip *args)
358{
359 struct tegra_dc_ext *ext = user->ext;
360 u8 idx_mask = 0;
361 int i;
362
363 for (i = 0; i < DC_N_WINDOWS; i++) {
364 int index = args->win[i].index;
365
366 if (index < 0)
367 continue;
368
369 idx_mask |= BIT(index);
370 }
371
372 for (i = DC_N_WINDOWS - 1; i >= 0; i--) {
373 if (!(idx_mask & BIT(i)))
374 continue;
375
376 mutex_unlock(&ext->win[i].lock);
377 }
378}
379
380static int sanitize_flip_args(struct tegra_dc_ext_user *user,
381 struct tegra_dc_ext_flip *args)
382{
383 int i, used_windows = 0;
384
385 for (i = 0; i < DC_N_WINDOWS; i++) {
386 int index = args->win[i].index;
387
388 if (index < 0)
389 continue;
390
391 if (index >= DC_N_WINDOWS)
392 return -EINVAL;
393
394 if (used_windows & BIT(index))
395 return -EINVAL;
396
397 used_windows |= BIT(index);
398 }
399
400 if (!used_windows)
401 return -EINVAL;
402
403 return 0;
404}
405
406static int tegra_dc_ext_flip(struct tegra_dc_ext_user *user,
407 struct tegra_dc_ext_flip *args)
408{
409 struct tegra_dc_ext *ext = user->ext;
410 struct tegra_dc_ext_flip_data *data;
411 int work_index;
412 int i, ret = 0;
413
414#ifdef CONFIG_ANDROID
415 int index_check[DC_N_WINDOWS] = {0, };
416 int zero_index_id = 0;
417#endif
418
419 if (!user->nvmap)
420 return -EFAULT;
421
422 ret = sanitize_flip_args(user, args);
423 if (ret)
424 return ret;
425
426 data = kzalloc(sizeof(*data), GFP_KERNEL);
427 if (!data)
428 return -ENOMEM;
429
430 INIT_WORK(&data->work, tegra_dc_ext_flip_worker);
431 data->ext = ext;
432
433#ifdef CONFIG_ANDROID
434 for (i = 0; i < DC_N_WINDOWS; i++) {
435 index_check[i] = args->win[i].index;
436 if (index_check[i] == 0)
437 zero_index_id = i;
438 }
439
440 if (index_check[DC_N_WINDOWS - 1] != 0) {
441 struct tegra_dc_ext_flip_windowattr win_temp;
442 win_temp = args->win[DC_N_WINDOWS - 1];
443 args->win[DC_N_WINDOWS - 1] = args->win[zero_index_id];
444 args->win[zero_index_id] = win_temp;
445 }
446#endif
447
448 for (i = 0; i < DC_N_WINDOWS; i++) {
449 struct tegra_dc_ext_flip_win *flip_win = &data->win[i];
450 int index = args->win[i].index;
451
452 memcpy(&flip_win->attr, &args->win[i], sizeof(flip_win->attr));
453
454 if (index < 0)
455 continue;
456
457 ret = tegra_dc_ext_pin_window(user, flip_win->attr.buff_id,
458 &flip_win->handle[TEGRA_DC_Y],
459 &flip_win->phys_addr);
460 if (ret)
461 goto fail_pin;
462
463 if (flip_win->attr.buff_id_u) {
464 ret = tegra_dc_ext_pin_window(user,
465 flip_win->attr.buff_id_u,
466 &flip_win->handle[TEGRA_DC_U],
467 &flip_win->phys_addr_u);
468 if (ret)
469 goto fail_pin;
470 } else {
471 flip_win->handle[TEGRA_DC_U] = NULL;
472 flip_win->phys_addr_u = 0;
473 }
474
475 if (flip_win->attr.buff_id_v) {
476 ret = tegra_dc_ext_pin_window(user,
477 flip_win->attr.buff_id_v,
478 &flip_win->handle[TEGRA_DC_V],
479 &flip_win->phys_addr_v);
480 if (ret)
481 goto fail_pin;
482 } else {
483 flip_win->handle[TEGRA_DC_V] = NULL;
484 flip_win->phys_addr_v = 0;
485 }
486 }
487
488 ret = lock_windows_for_flip(user, args);
489 if (ret)
490 goto fail_pin;
491
492 if (!ext->enabled) {
493 ret = -ENXIO;
494 goto unlock;
495 }
496
497 for (i = 0; i < DC_N_WINDOWS; i++) {
498 u32 syncpt_max;
499 int index = args->win[i].index;
500 struct tegra_dc_win *win;
501 struct tegra_dc_ext_win *ext_win;
502
503 if (index < 0)
504 continue;
505
506 win = tegra_dc_get_window(ext->dc, index);
507 ext_win = &ext->win[index];
508
509 syncpt_max = tegra_dc_incr_syncpt_max(ext->dc, index);
510
511 data->win[i].syncpt_max = syncpt_max;
512
513 /*
514 * Any of these windows' syncpoints should be equivalent for
515 * the client, so we just send back an arbitrary one of them
516 */
517 args->post_syncpt_val = syncpt_max;
518 args->post_syncpt_id = tegra_dc_get_syncpt_id(ext->dc, index);
519 work_index = index;
520
521 atomic_inc(&ext->win[work_index].nr_pending_flips);
522 }
523 queue_work(ext->win[work_index].flip_wq, &data->work);
524
525 unlock_windows_for_flip(user, args);
526
527 return 0;
528
529unlock:
530 unlock_windows_for_flip(user, args);
531
532fail_pin:
533 for (i = 0; i < DC_N_WINDOWS; i++) {
534 int j;
535 for (j = 0; j < TEGRA_DC_NUM_PLANES; j++) {
536 if (!data->win[i].handle[j])
537 continue;
538
539 nvmap_unpin(ext->nvmap, data->win[i].handle[j]);
540 nvmap_free(ext->nvmap, data->win[i].handle[j]);
541 }
542 }
543 kfree(data);
544
545 return ret;
546}
547
548static int tegra_dc_ext_set_csc(struct tegra_dc_ext_user *user,
549 struct tegra_dc_ext_csc *new_csc)
550{
551 unsigned int index = new_csc->win_index;
552 struct tegra_dc *dc = user->ext->dc;
553 struct tegra_dc_ext_win *ext_win;
554 struct tegra_dc_csc *csc;
555
556 if (index >= DC_N_WINDOWS)
557 return -EINVAL;
558
559 ext_win = &user->ext->win[index];
560 csc = &dc->windows[index].csc;
561
562 mutex_lock(&ext_win->lock);
563
564 if (ext_win->user != user) {
565 mutex_unlock(&ext_win->lock);
566 return -EACCES;
567 }
568
569 csc->yof = new_csc->yof;
570 csc->kyrgb = new_csc->kyrgb;
571 csc->kur = new_csc->kur;
572 csc->kvr = new_csc->kvr;
573 csc->kug = new_csc->kug;
574 csc->kvg = new_csc->kvg;
575 csc->kub = new_csc->kub;
576 csc->kvb = new_csc->kvb;
577
578 tegra_dc_update_csc(dc, index);
579
580 mutex_unlock(&ext_win->lock);
581
582 return 0;
583}
584
585static int set_lut_channel(u16 *channel_from_user,
586 u8 *channel_to,
587 u32 start,
588 u32 len)
589{
590 int i;
591 u16 lut16bpp[256];
592
593 if (channel_from_user) {
594 if (copy_from_user(lut16bpp, channel_from_user, len<<1))
595 return 1;
596
597 for (i = 0; i < len; i++)
598 channel_to[start+i] = lut16bpp[i]>>8;
599 } else {
600 for (i = 0; i < len; i++)
601 channel_to[start+i] = start+i;
602 }
603
604 return 0;
605}
606
607static int tegra_dc_ext_set_lut(struct tegra_dc_ext_user *user,
608 struct tegra_dc_ext_lut *new_lut)
609{
610 int err;
611 unsigned int index = new_lut->win_index;
612 u32 start = new_lut->start;
613 u32 len = new_lut->len;
614
615 struct tegra_dc *dc = user->ext->dc;
616 struct tegra_dc_ext_win *ext_win;
617 struct tegra_dc_lut *lut;
618
619 if (index >= DC_N_WINDOWS)
620 return -EINVAL;
621
622 if ((start >= 256) || (len > 256) || ((start + len) > 256))
623 return -EINVAL;
624
625 ext_win = &user->ext->win[index];
626 lut = &dc->windows[index].lut;
627
628 mutex_lock(&ext_win->lock);
629
630 if (ext_win->user != user) {
631 mutex_unlock(&ext_win->lock);
632 return -EACCES;
633 }
634
635 err = set_lut_channel(new_lut->r, lut->r, start, len) |
636 set_lut_channel(new_lut->g, lut->g, start, len) |
637 set_lut_channel(new_lut->b, lut->b, start, len);
638
639 if (err) {
640 mutex_unlock(&ext_win->lock);
641 return -EFAULT;
642 }
643
644 tegra_dc_update_lut(dc, index,
645 new_lut->flags & TEGRA_DC_EXT_LUT_FLAGS_FBOVERRIDE);
646
647 mutex_unlock(&ext_win->lock);
648
649 return 0;
650}
651
652static u32 tegra_dc_ext_get_vblank_syncpt(struct tegra_dc_ext_user *user)
653{
654 struct tegra_dc *dc = user->ext->dc;
655
656 return dc->vblank_syncpt;
657}
658
659static int tegra_dc_ext_get_status(struct tegra_dc_ext_user *user,
660 struct tegra_dc_ext_status *status)
661{
662 struct tegra_dc *dc = user->ext->dc;
663
664 memset(status, 0, sizeof(*status));
665
666 if (dc->enabled)
667 status->flags |= TEGRA_DC_EXT_FLAGS_ENABLED;
668
669 return 0;
670}
671
672static long tegra_dc_ioctl(struct file *filp, unsigned int cmd,
673 unsigned long arg)
674{
675 void __user *user_arg = (void __user *)arg;
676 struct tegra_dc_ext_user *user = filp->private_data;
677
678 switch (cmd) {
679 case TEGRA_DC_EXT_SET_NVMAP_FD:
680 return tegra_dc_ext_set_nvmap_fd(user, arg);
681
682 case TEGRA_DC_EXT_GET_WINDOW:
683 return tegra_dc_ext_get_window(user, arg);
684 case TEGRA_DC_EXT_PUT_WINDOW:
685 return tegra_dc_ext_put_window(user, arg);
686
687 case TEGRA_DC_EXT_FLIP:
688 {
689 struct tegra_dc_ext_flip args;
690 int ret;
691
692 if (copy_from_user(&args, user_arg, sizeof(args)))
693 return -EFAULT;
694
695 ret = tegra_dc_ext_flip(user, &args);
696
697 if (copy_to_user(user_arg, &args, sizeof(args)))
698 return -EFAULT;
699
700 return ret;
701 }
702
703 case TEGRA_DC_EXT_GET_CURSOR:
704 return tegra_dc_ext_get_cursor(user);
705 case TEGRA_DC_EXT_PUT_CURSOR:
706 return tegra_dc_ext_put_cursor(user);
707 case TEGRA_DC_EXT_SET_CURSOR_IMAGE:
708 {
709 struct tegra_dc_ext_cursor_image args;
710
711 if (copy_from_user(&args, user_arg, sizeof(args)))
712 return -EFAULT;
713
714 return tegra_dc_ext_set_cursor_image(user, &args);
715 }
716 case TEGRA_DC_EXT_SET_CURSOR:
717 {
718 struct tegra_dc_ext_cursor args;
719
720 if (copy_from_user(&args, user_arg, sizeof(args)))
721 return -EFAULT;
722
723 return tegra_dc_ext_set_cursor(user, &args);
724 }
725
726 case TEGRA_DC_EXT_SET_CSC:
727 {
728 struct tegra_dc_ext_csc args;
729
730 if (copy_from_user(&args, user_arg, sizeof(args)))
731 return -EFAULT;
732
733 return tegra_dc_ext_set_csc(user, &args);
734 }
735
736 case TEGRA_DC_EXT_GET_VBLANK_SYNCPT:
737 {
738 u32 syncpt = tegra_dc_ext_get_vblank_syncpt(user);
739
740 if (copy_to_user(user_arg, &syncpt, sizeof(syncpt)))
741 return -EFAULT;
742
743 return 0;
744 }
745
746 case TEGRA_DC_EXT_GET_STATUS:
747 {
748 struct tegra_dc_ext_status args;
749 int ret;
750
751 ret = tegra_dc_ext_get_status(user, &args);
752
753 if (copy_to_user(user_arg, &args, sizeof(args)))
754 return -EFAULT;
755
756 return ret;
757 }
758
759 case TEGRA_DC_EXT_SET_LUT:
760 {
761 struct tegra_dc_ext_lut args;
762
763 if (copy_from_user(&args, user_arg, sizeof(args)))
764 return -EFAULT;
765
766 return tegra_dc_ext_set_lut(user, &args);
767 }
768
769 default:
770 return -EINVAL;
771 }
772}
773
774static int tegra_dc_open(struct inode *inode, struct file *filp)
775{
776 struct tegra_dc_ext_user *user;
777 struct tegra_dc_ext *ext;
778
779 user = kzalloc(sizeof(*user), GFP_KERNEL);
780 if (!user)
781 return -ENOMEM;
782
783 ext = container_of(inode->i_cdev, struct tegra_dc_ext, cdev);
784 user->ext = ext;
785
786 filp->private_data = user;
787
788 return 0;
789}
790
791static int tegra_dc_release(struct inode *inode, struct file *filp)
792{
793 struct tegra_dc_ext_user *user = filp->private_data;
794 struct tegra_dc_ext *ext = user->ext;
795 unsigned int i;
796
797 for (i = 0; i < DC_N_WINDOWS; i++) {
798 if (ext->win[i].user == user)
799 tegra_dc_ext_put_window(user, i);
800 }
801 if (ext->cursor.user == user)
802 tegra_dc_ext_put_cursor(user);
803
804 if (user->nvmap)
805 nvmap_client_put(user->nvmap);
806
807 kfree(user);
808
809 return 0;
810}
811
812static int tegra_dc_ext_setup_windows(struct tegra_dc_ext *ext)
813{
814 int i, ret;
815
816 for (i = 0; i < ext->dc->n_windows; i++) {
817 struct tegra_dc_ext_win *win = &ext->win[i];
818 char name[32];
819
820 win->ext = ext;
821 win->idx = i;
822
823 snprintf(name, sizeof(name), "tegradc.%d/%c",
824 ext->dc->ndev->id, 'a' + i);
825 win->flip_wq = create_singlethread_workqueue(name);
826 if (!win->flip_wq) {
827 ret = -ENOMEM;
828 goto cleanup;
829 }
830
831 mutex_init(&win->lock);
832 }
833
834 return 0;
835
836cleanup:
837 while (i--) {
838 struct tegra_dc_ext_win *win = &ext->win[i];
839 destroy_workqueue(win->flip_wq);
840 }
841
842 return ret;
843}
844
845static const struct file_operations tegra_dc_devops = {
846 .owner = THIS_MODULE,
847 .open = tegra_dc_open,
848 .release = tegra_dc_release,
849 .unlocked_ioctl = tegra_dc_ioctl,
850};
851
852struct tegra_dc_ext *tegra_dc_ext_register(struct nvhost_device *ndev,
853 struct tegra_dc *dc)
854{
855 int ret;
856 struct tegra_dc_ext *ext;
857 int devno;
858
859 ext = kzalloc(sizeof(*ext), GFP_KERNEL);
860 if (!ext)
861 return ERR_PTR(-ENOMEM);
862
863 BUG_ON(!tegra_dc_ext_devno);
864 devno = tegra_dc_ext_devno + head_count + 1;
865
866 cdev_init(&ext->cdev, &tegra_dc_devops);
867 ext->cdev.owner = THIS_MODULE;
868 ret = cdev_add(&ext->cdev, devno, 1);
869 if (ret) {
870 dev_err(&ndev->dev, "Failed to create character device\n");
871 goto cleanup_alloc;
872 }
873
874 ext->dev = device_create(tegra_dc_ext_class,
875 &ndev->dev,
876 devno,
877 NULL,
878 "tegra_dc_%d",
879 ndev->id);
880
881 if (IS_ERR(ext->dev)) {
882 ret = PTR_ERR(ext->dev);
883 goto cleanup_cdev;
884 }
885
886 ext->dc = dc;
887
888 ext->nvmap = nvmap_create_client(nvmap_dev, "tegra_dc_ext");
889 if (!ext->nvmap) {
890 ret = -ENOMEM;
891 goto cleanup_device;
892 }
893
894 ret = tegra_dc_ext_setup_windows(ext);
895 if (ret)
896 goto cleanup_nvmap;
897
898 mutex_init(&ext->cursor.lock);
899
900 head_count++;
901
902 return ext;
903
904cleanup_nvmap:
905 nvmap_client_put(ext->nvmap);
906
907cleanup_device:
908 device_del(ext->dev);
909
910cleanup_cdev:
911 cdev_del(&ext->cdev);
912
913cleanup_alloc:
914 kfree(ext);
915
916 return ERR_PTR(ret);
917}
918
919void tegra_dc_ext_unregister(struct tegra_dc_ext *ext)
920{
921 int i;
922
923 for (i = 0; i < ext->dc->n_windows; i++) {
924 struct tegra_dc_ext_win *win = &ext->win[i];
925
926 flush_workqueue(win->flip_wq);
927 destroy_workqueue(win->flip_wq);
928 }
929
930 nvmap_client_put(ext->nvmap);
931 device_del(ext->dev);
932 cdev_del(&ext->cdev);
933
934 kfree(ext);
935
936 head_count--;
937}
938
939int __init tegra_dc_ext_module_init(void)
940{
941 int ret;
942
943 tegra_dc_ext_class = class_create(THIS_MODULE, "tegra_dc_ext");
944 if (!tegra_dc_ext_class) {
945 printk(KERN_ERR "tegra_dc_ext: failed to create class\n");
946 return -ENOMEM;
947 }
948
949 /* Reserve one character device per head, plus the control device */
950 ret = alloc_chrdev_region(&tegra_dc_ext_devno,
951 0, TEGRA_MAX_DC + 1,
952 "tegra_dc_ext");
953 if (ret)
954 goto cleanup_class;
955
956 ret = tegra_dc_ext_control_init();
957 if (ret)
958 goto cleanup_region;
959
960 return 0;
961
962cleanup_region:
963 unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC);
964
965cleanup_class:
966 class_destroy(tegra_dc_ext_class);
967
968 return ret;
969}
970
971void __exit tegra_dc_ext_module_exit(void)
972{
973 unregister_chrdev_region(tegra_dc_ext_devno, TEGRA_MAX_DC);
974 class_destroy(tegra_dc_ext_class);
975}
diff --git a/drivers/video/tegra/dc/ext/events.c b/drivers/video/tegra/dc/ext/events.c
new file mode 100644
index 00000000000..150a1501fce
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/events.c
@@ -0,0 +1,197 @@
1/*
2 * drivers/video/tegra/dc/ext/events.c
3 *
4 * Copyright (C) 2011, NVIDIA Corporation
5 *
6 * Author: Robert Morell <rmorell@nvidia.com>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 */
18
19#include <linux/err.h>
20#include <linux/fs.h>
21#include <linux/list.h>
22#include <linux/poll.h>
23#include <linux/sched.h>
24#include <linux/slab.h>
25#include <linux/uaccess.h>
26
27#include "tegra_dc_ext_priv.h"
28
29static DECLARE_WAIT_QUEUE_HEAD(event_wait);
30
31unsigned int tegra_dc_ext_event_poll(struct file *filp, poll_table *wait)
32{
33 struct tegra_dc_ext_control_user *user = filp->private_data;
34 unsigned int mask = 0;
35
36 poll_wait(filp, &event_wait, wait);
37
38 if (atomic_read(&user->num_events))
39 mask |= POLLIN;
40
41 return mask;
42}
43
44static int get_next_event(struct tegra_dc_ext_control_user *user,
45 struct tegra_dc_ext_event_list *event,
46 bool block)
47{
48 struct list_head *list = &user->event_list;
49 struct tegra_dc_ext_event_list *next_event;
50 int ret;
51
52 if (block) {
53 ret = wait_event_interruptible(event_wait,
54 atomic_read(&user->num_events));
55
56 if (unlikely(ret)) {
57 if (ret == -ERESTARTSYS)
58 return -EAGAIN;
59 return ret;
60 }
61 } else {
62 if (!atomic_read(&user->num_events))
63 return 0;
64 }
65
66 mutex_lock(&user->lock);
67
68 BUG_ON(list_empty(list));
69 next_event = list_first_entry(list, struct tegra_dc_ext_event_list,
70 list);
71 *event = *next_event;
72 list_del(&next_event->list);
73 kfree(next_event);
74
75 atomic_dec(&user->num_events);
76
77 mutex_unlock(&user->lock);
78
79 return 1;
80}
81
82ssize_t tegra_dc_ext_event_read(struct file *filp, char __user *buf,
83 size_t size, loff_t *ppos)
84{
85 struct tegra_dc_ext_control_user *user = filp->private_data;
86 struct tegra_dc_ext_event_list event_elem;
87 struct tegra_dc_ext_event *event = &event_elem.event;
88 ssize_t retval = 0, to_copy, event_size, pending;
89 loff_t previously_copied = 0;
90 char *to_copy_ptr;
91
92 if (size == 0)
93 return 0;
94
95 if (user->partial_copy) {
96 /*
97 * We didn't transfer the entire event last time, need to
98 * finish it up
99 */
100 event_elem = user->event_to_copy;
101 previously_copied = user->partial_copy;
102 } else {
103 /* Get the next event, if any */
104 pending = get_next_event(user, &event_elem,
105 !(filp->f_flags & O_NONBLOCK));
106 if (pending <= 0)
107 return pending;
108 }
109
110 /* Write the event to the user */
111 event_size = sizeof(*event) + event->data_size;
112 BUG_ON(event_size <= previously_copied);
113 event_size -= previously_copied;
114
115 to_copy_ptr = (char *)event + previously_copied;
116 to_copy = min_t(ssize_t, size, event_size);
117 if (copy_to_user(buf, to_copy_ptr, to_copy)) {
118 retval = -EFAULT;
119 to_copy = 0;
120 }
121
122 /* Note that we currently only deliver one event at a time */
123
124 if (event_size > to_copy) {
125 /*
126 * We were only able to copy part of this event. Stash it for
127 * next time.
128 */
129 user->event_to_copy = event_elem;
130 user->partial_copy = previously_copied + to_copy;
131 } else {
132 user->partial_copy = 0;
133 }
134
135 return to_copy ? to_copy : retval;
136}
137
138static int tegra_dc_ext_queue_event(struct tegra_dc_ext_control *control,
139 struct tegra_dc_ext_event *event)
140{
141 struct list_head *cur;
142 int retval = 0;
143
144 mutex_lock(&control->lock);
145 list_for_each(cur, &control->users) {
146 struct tegra_dc_ext_control_user *user;
147 struct tegra_dc_ext_event_list *ev_list;
148
149 user = container_of(cur, struct tegra_dc_ext_control_user,
150 list);
151 mutex_lock(&user->lock);
152
153 if (!(user->event_mask & event->type)) {
154 mutex_unlock(&user->lock);
155 continue;
156 }
157
158 ev_list = kmalloc(sizeof(*ev_list), GFP_KERNEL);
159 if (!ev_list) {
160 retval = -ENOMEM;
161 mutex_unlock(&user->lock);
162 continue;
163 }
164
165 memcpy(&ev_list->event, event,
166 sizeof(*event) + event->data_size);
167
168 list_add_tail(&ev_list->list, &user->event_list);
169
170 atomic_inc(&user->num_events);
171
172 mutex_unlock(&user->lock);
173 }
174 mutex_unlock(&control->lock);
175
176 /* Is it worth it to track waiters with more granularity? */
177 wake_up(&event_wait);
178
179 return retval;
180}
181
182int tegra_dc_ext_queue_hotplug(struct tegra_dc_ext_control *control, int output)
183{
184 struct {
185 struct tegra_dc_ext_event event;
186 struct tegra_dc_ext_control_event_hotplug hotplug;
187 } __packed pack;
188
189 pack.event.type = TEGRA_DC_EXT_EVENT_HOTPLUG;
190 pack.event.data_size = sizeof(pack.hotplug);
191
192 pack.hotplug.handle = output;
193
194 tegra_dc_ext_queue_event(control, &pack.event);
195
196 return 0;
197}
diff --git a/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
new file mode 100644
index 00000000000..95a637d5a52
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
@@ -0,0 +1,147 @@
1/*
2 * drivers/video/tegra/dc/ext/tegra_dc_ext_priv.h
3 *
4 * Copyright (C) 2011, NVIDIA Corporation
5 *
6 * Author: Robert Morell <rmorell@nvidia.com>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 */
18
19#ifndef __TEGRA_DC_EXT_PRIV_H
20#define __TEGRA_DC_EXT_PRIV_H
21
22#include <linux/cdev.h>
23#include <linux/list.h>
24#include <linux/mutex.h>
25#include <linux/poll.h>
26
27#include <mach/dc.h>
28#include <mach/nvmap.h>
29
30#include <video/tegra_dc_ext.h>
31
32struct tegra_dc_ext;
33
34struct tegra_dc_ext_user {
35 struct tegra_dc_ext *ext;
36 struct nvmap_client *nvmap;
37};
38
39enum {
40 TEGRA_DC_Y,
41 TEGRA_DC_U,
42 TEGRA_DC_V,
43 TEGRA_DC_NUM_PLANES,
44};
45
46struct tegra_dc_ext_win {
47 struct tegra_dc_ext *ext;
48
49 int idx;
50
51 struct tegra_dc_ext_user *user;
52
53 struct mutex lock;
54
55 /* Current nvmap handle (if any) for Y, U, V planes */
56 struct nvmap_handle_ref *cur_handle[TEGRA_DC_NUM_PLANES];
57
58 struct workqueue_struct *flip_wq;
59
60 atomic_t nr_pending_flips;
61};
62
63struct tegra_dc_ext {
64 struct tegra_dc *dc;
65
66 struct cdev cdev;
67 struct device *dev;
68
69 struct nvmap_client *nvmap;
70
71 struct tegra_dc_ext_win win[DC_N_WINDOWS];
72
73 struct {
74 struct tegra_dc_ext_user *user;
75 struct nvmap_handle_ref *cur_handle;
76 struct mutex lock;
77 } cursor;
78
79 bool enabled;
80};
81
82#define TEGRA_DC_EXT_EVENT_MASK_ALL \
83 TEGRA_DC_EXT_EVENT_HOTPLUG
84
85#define TEGRA_DC_EXT_EVENT_MAX_SZ 8
86
87struct tegra_dc_ext_event_list {
88 struct tegra_dc_ext_event event;
89 /* The data field _must_ follow the event field. */
90 char data[TEGRA_DC_EXT_EVENT_MAX_SZ];
91
92 struct list_head list;
93};
94
95#define TEGRA_DC_EXT_CAPABILITIES \
96 TEGRA_DC_EXT_CAPABILITIES_CURSOR_MODE
97
98struct tegra_dc_ext_control_user {
99 struct tegra_dc_ext_control *control;
100
101 struct list_head event_list;
102 atomic_t num_events;
103
104 u32 event_mask;
105
106 struct tegra_dc_ext_event_list event_to_copy;
107 loff_t partial_copy;
108
109 struct mutex lock;
110
111 struct list_head list;
112};
113
114struct tegra_dc_ext_control {
115 struct cdev cdev;
116 struct device *dev;
117
118 struct list_head users;
119
120 struct mutex lock;
121};
122
123extern int tegra_dc_ext_devno;
124extern struct class *tegra_dc_ext_class;
125
126extern int tegra_dc_ext_pin_window(struct tegra_dc_ext_user *user, u32 id,
127 struct nvmap_handle_ref **handle,
128 dma_addr_t *phys_addr);
129
130extern int tegra_dc_ext_get_cursor(struct tegra_dc_ext_user *user);
131extern int tegra_dc_ext_put_cursor(struct tegra_dc_ext_user *user);
132extern int tegra_dc_ext_set_cursor_image(struct tegra_dc_ext_user *user,
133 struct tegra_dc_ext_cursor_image *);
134extern int tegra_dc_ext_set_cursor(struct tegra_dc_ext_user *user,
135 struct tegra_dc_ext_cursor *);
136
137extern int tegra_dc_ext_control_init(void);
138
139extern int tegra_dc_ext_queue_hotplug(struct tegra_dc_ext_control *,
140 int output);
141extern ssize_t tegra_dc_ext_event_read(struct file *filp, char __user *buf,
142 size_t size, loff_t *ppos);
143extern unsigned int tegra_dc_ext_event_poll(struct file *, poll_table *);
144
145extern int tegra_dc_ext_get_num_outputs(void);
146
147#endif /* __TEGRA_DC_EXT_PRIV_H */
diff --git a/drivers/video/tegra/dc/ext/util.c b/drivers/video/tegra/dc/ext/util.c
new file mode 100644
index 00000000000..747085579f1
--- /dev/null
+++ b/drivers/video/tegra/dc/ext/util.c
@@ -0,0 +1,78 @@
1/*
2 * drivers/video/tegra/dc/ext/util.c
3 *
4 * Copyright (C) 2011, NVIDIA Corporation
5 *
6 * Author: Robert Morell <rmorell@nvidia.com>
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 */
18
19#include <linux/err.h>
20#include <linux/types.h>
21
22#include <mach/dc.h>
23#include <mach/nvmap.h>
24
25/* ugh */
26#include "../../nvmap/nvmap.h"
27
28#include "tegra_dc_ext_priv.h"
29
30int tegra_dc_ext_pin_window(struct tegra_dc_ext_user *user, u32 id,
31 struct nvmap_handle_ref **handle,
32 dma_addr_t *phys_addr)
33{
34 struct tegra_dc_ext *ext = user->ext;
35 struct nvmap_handle_ref *win_dup;
36 struct nvmap_handle *win_handle;
37 dma_addr_t phys;
38
39 if (!id) {
40 *handle = NULL;
41 *phys_addr = -1;
42
43 return 0;
44 }
45
46 /*
47 * Take a reference to the buffer using the user's nvmap context, to
48 * make sure they have permissions to access it.
49 */
50 win_handle = nvmap_get_handle_id(user->nvmap, id);
51 if (!win_handle)
52 return -EACCES;
53
54 /*
55 * Duplicate the buffer's handle into the dc_ext driver's nvmap
56 * context, to ensure that the handle won't be freed as long as it is
57 * in use by display.
58 */
59 win_dup = nvmap_duplicate_handle_id(ext->nvmap, id);
60
61 /* Release the reference we took in the user's context above */
62 nvmap_handle_put(win_handle);
63
64 if (IS_ERR(win_dup))
65 return PTR_ERR(win_dup);
66
67 phys = nvmap_pin(ext->nvmap, win_dup);
68 /* XXX this isn't correct for non-pointers... */
69 if (IS_ERR((void *)phys)) {
70 nvmap_free(ext->nvmap, win_dup);
71 return PTR_ERR((void *)phys);
72 }
73
74 *phys_addr = phys;
75 *handle = win_dup;
76
77 return 0;
78}
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
new file mode 100644
index 00000000000..cb401a167fd
--- /dev/null
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -0,0 +1,2381 @@
1/*
2 * drivers/video/tegra/dc/hdmi.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2010-2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/clk.h>
21#include <linux/delay.h>
22#include <linux/err.h>
23#include <linux/fb.h>
24#include <linux/gpio.h>
25#include <linux/interrupt.h>
26#include <linux/kernel.h>
27#include <linux/slab.h>
28#include <linux/spinlock.h>
29#ifdef CONFIG_SWITCH
30#include <linux/switch.h>
31#endif
32#include <linux/workqueue.h>
33#include <linux/debugfs.h>
34#include <linux/seq_file.h>
35#include <linux/device.h>
36
37#include <mach/clk.h>
38#include <mach/dc.h>
39#include <mach/fb.h>
40#include <linux/nvhost.h>
41#include <mach/hdmi-audio.h>
42
43#include <video/tegrafb.h>
44
45#include "dc_reg.h"
46#include "dc_priv.h"
47#include "hdmi_reg.h"
48#include "hdmi.h"
49#include "edid.h"
50#include "nvhdcp.h"
51
52/* datasheet claims this will always be 216MHz */
53#define HDMI_AUDIOCLK_FREQ 216000000
54
55#define HDMI_REKEY_DEFAULT 56
56
57#define HDMI_ELD_RESERVED1_INDEX 1
58#define HDMI_ELD_RESERVED2_INDEX 3
59#define HDMI_ELD_VER_INDEX 0
60#define HDMI_ELD_BASELINE_LEN_INDEX 2
61#define HDMI_ELD_CEA_VER_MNL_INDEX 4
62#define HDMI_ELD_SAD_CNT_CON_TYP_SAI_HDCP_INDEX 5
63#define HDMI_ELD_AUD_SYNC_DELAY_INDEX 6
64#define HDMI_ELD_SPK_ALLOC_INDEX 7
65#define HDMI_ELD_PORT_ID_INDEX 8
66#define HDMI_ELD_MANF_NAME_INDEX 16
67#define HDMI_ELD_PRODUCT_CODE_INDEX 18
68#define HDMI_ELD_MONITOR_NAME_INDEX 20
69
70struct tegra_dc_hdmi_data {
71 struct tegra_dc *dc;
72 struct tegra_edid *edid;
73 struct tegra_edid_hdmi_eld eld;
74 struct tegra_nvhdcp *nvhdcp;
75 struct delayed_work work;
76
77 struct resource *base_res;
78 void __iomem *base;
79 struct clk *clk;
80
81 struct clk *disp1_clk;
82 struct clk *disp2_clk;
83 struct clk *hda_clk;
84 struct clk *hda2codec_clk;
85 struct clk *hda2hdmi_clk;
86
87#ifdef CONFIG_SWITCH
88 struct switch_dev hpd_switch;
89#endif
90
91 spinlock_t suspend_lock;
92 bool suspended;
93 bool eld_retrieved;
94 bool clk_enabled;
95 unsigned audio_freq;
96 unsigned audio_source;
97
98 bool dvi;
99};
100
101struct tegra_dc_hdmi_data *dc_hdmi;
102
103const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
104 /* 1280x720p 60hz: EIA/CEA-861-B Format 4 */
105 {
106 .xres = 1280,
107 .yres = 720,
108 .pixclock = KHZ2PICOS(74250),
109 .hsync_len = 40, /* h_sync_width */
110 .vsync_len = 5, /* v_sync_width */
111 .left_margin = 220, /* h_back_porch */
112 .upper_margin = 20, /* v_back_porch */
113 .right_margin = 110, /* h_front_porch */
114 .lower_margin = 5, /* v_front_porch */
115 .vmode = FB_VMODE_NONINTERLACED,
116 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
117 },
118
119 /* 1280x720p 60hz: EIA/CEA-861-B Format 4 (Stereo)*/
120 {
121 .xres = 1280,
122 .yres = 720,
123 .pixclock = KHZ2PICOS(74250),
124 .hsync_len = 40, /* h_sync_width */
125 .vsync_len = 5, /* v_sync_width */
126 .left_margin = 220, /* h_back_porch */
127 .upper_margin = 20, /* v_back_porch */
128 .right_margin = 110, /* h_front_porch */
129 .lower_margin = 5, /* v_front_porch */
130 .vmode = FB_VMODE_NONINTERLACED |
131#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
132 FB_VMODE_STEREO_FRAME_PACK,
133#else
134 FB_VMODE_STEREO_LEFT_RIGHT,
135#endif
136 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
137 },
138
139 /* 720x480p 59.94hz: EIA/CEA-861-B Formats 2 & 3 */
140 {
141 .xres = 720,
142 .yres = 480,
143 .pixclock = KHZ2PICOS(27000),
144 .hsync_len = 62, /* h_sync_width */
145 .vsync_len = 6, /* v_sync_width */
146 .left_margin = 60, /* h_back_porch */
147 .upper_margin = 30, /* v_back_porch */
148 .right_margin = 16, /* h_front_porch */
149 .lower_margin = 9, /* v_front_porch */
150 .vmode = FB_VMODE_NONINTERLACED,
151 .sync = 0,
152 },
153
154 /* 640x480p 60hz: EIA/CEA-861-B Format 1 */
155 {
156 .xres = 640,
157 .yres = 480,
158 .pixclock = KHZ2PICOS(25200),
159 .hsync_len = 96, /* h_sync_width */
160 .vsync_len = 2, /* v_sync_width */
161 .left_margin = 48, /* h_back_porch */
162 .upper_margin = 33, /* v_back_porch */
163 .right_margin = 16, /* h_front_porch */
164 .lower_margin = 10, /* v_front_porch */
165 .vmode = FB_VMODE_NONINTERLACED,
166 .sync = 0,
167 },
168
169 /* 720x576p 50hz EIA/CEA-861-B Formats 17 & 18 */
170 {
171 .xres = 720,
172 .yres = 576,
173 .pixclock = KHZ2PICOS(27000),
174 .hsync_len = 64, /* h_sync_width */
175 .vsync_len = 5, /* v_sync_width */
176 .left_margin = 68, /* h_back_porch */
177 .upper_margin = 39, /* v_back_porch */
178 .right_margin = 12, /* h_front_porch */
179 .lower_margin = 5, /* v_front_porch */
180 .vmode = FB_VMODE_NONINTERLACED,
181 .sync = 0,
182 },
183
184 /* 1920x1080p 23.98/24hz: EIA/CEA-861-B Format 32 (Stereo)*/
185 {
186 .xres = 1920,
187 .yres = 1080,
188 .pixclock = KHZ2PICOS(74250),
189 .hsync_len = 44, /* h_sync_width */
190 .vsync_len = 5, /* v_sync_width */
191 .left_margin = 148, /* h_back_porch */
192 .upper_margin = 36, /* v_back_porch */
193 .right_margin = 638, /* h_front_porch */
194 .lower_margin = 4, /* v_front_porch */
195 .vmode = FB_VMODE_NONINTERLACED |
196#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
197 FB_VMODE_STEREO_FRAME_PACK,
198#else
199 FB_VMODE_STEREO_LEFT_RIGHT,
200#endif
201 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
202 },
203
204 /* 1920x1080p 30Hz EIA/CEA-861-B Format 34 */
205 {
206 .xres = 1920,
207 .yres = 1080,
208 .pixclock = KHZ2PICOS(74250),
209 .hsync_len = 44, /* h_sync_width */
210 .vsync_len = 5, /* v_sync_width */
211 .left_margin = 148, /* h_back_porch */
212 .upper_margin = 36, /* v_back_porch */
213 .right_margin = 88, /* h_front_porch */
214 .lower_margin = 4, /* v_front_porch */
215 .vmode = FB_VMODE_NONINTERLACED,
216 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
217 },
218 /* 1920x1080p 59.94/60hz EIA/CEA-861-B Format 16 */
219 {
220 .xres = 1920,
221 .yres = 1080,
222 .pixclock = KHZ2PICOS(148500),
223 .hsync_len = 44, /* h_sync_width */
224 .vsync_len = 5, /* v_sync_width */
225 .left_margin = 148, /* h_back_porch */
226 .upper_margin = 36, /* v_back_porch */
227 .right_margin = 88, /* h_front_porch */
228 .lower_margin = 4, /* v_front_porch */
229 .vmode = FB_VMODE_NONINTERLACED,
230 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
231 },
232
233 /*
234 * Few VGA/SVGA modes to support monitors with lower
235 * resolutions or to support HDMI<->DVI connection
236 */
237
238 /* 640x480p 75hz */
239 {
240 .xres = 640,
241 .yres = 480,
242 .pixclock = KHZ2PICOS(31500),
243 .hsync_len = 96, /* h_sync_width */
244 .vsync_len = 2, /* v_sync_width */
245 .left_margin = 48, /* h_back_porch */
246 .upper_margin = 32, /* v_back_porch */
247 .right_margin = 16, /* h_front_porch */
248 .lower_margin = 1, /* v_front_porch */
249 .vmode = FB_VMODE_NONINTERLACED,
250 .sync = 0,
251 },
252 /* 720x400p 59hz */
253 {
254 .xres = 720,
255 .yres = 400,
256 .pixclock = KHZ2PICOS(35500),
257 .hsync_len = 72, /* h_sync_width */
258 .vsync_len = 3, /* v_sync_width */
259 .left_margin = 108, /* h_back_porch */
260 .upper_margin = 42, /* v_back_porch */
261 .right_margin = 36, /* h_front_porch */
262 .lower_margin = 1, /* v_front_porch */
263 .vmode = FB_VMODE_NONINTERLACED,
264 .sync = FB_SYNC_VERT_HIGH_ACT,
265 },
266 /* 800x600p 60hz */
267 {
268 .xres = 800,
269 .yres = 600,
270 .pixclock = KHZ2PICOS(40000),
271 .hsync_len = 128, /* h_sync_width */
272 .vsync_len = 4, /* v_sync_width */
273 .left_margin = 88, /* h_back_porch */
274 .upper_margin = 23, /* v_back_porch */
275 .right_margin = 40, /* h_front_porch */
276 .lower_margin = 1, /* v_front_porch */
277 .vmode = FB_VMODE_NONINTERLACED,
278 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
279 },
280 /* 800x600p 75hz */
281 {
282 .xres = 800,
283 .yres = 600,
284 .pixclock = KHZ2PICOS(49500),
285 .hsync_len = 80, /* h_sync_width */
286 .vsync_len = 2, /* v_sync_width */
287 .left_margin = 160, /* h_back_porch */
288 .upper_margin = 21, /* v_back_porch */
289 .right_margin = 16, /* h_front_porch */
290 .lower_margin = 1, /* v_front_porch */
291 .vmode = FB_VMODE_NONINTERLACED,
292 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
293 },
294 /* 1024x768p 60hz */
295 {
296 .xres = 1024,
297 .yres = 768,
298 .pixclock = KHZ2PICOS(65000),
299 .hsync_len = 136, /* h_sync_width */
300 .vsync_len = 6, /* v_sync_width */
301 .left_margin = 160, /* h_back_porch */
302 .upper_margin = 29, /* v_back_porch */
303 .right_margin = 24, /* h_front_porch */
304 .lower_margin = 3, /* v_front_porch */
305 .vmode = FB_VMODE_NONINTERLACED,
306 .sync = 0,
307 },
308 /* 1024x768p 75hz */
309 {
310 .xres = 1024,
311 .yres = 768,
312 .pixclock = KHZ2PICOS(78800),
313 .hsync_len = 96, /* h_sync_width */
314 .vsync_len = 3, /* v_sync_width */
315 .left_margin = 176, /* h_back_porch */
316 .upper_margin = 28, /* v_back_porch */
317 .right_margin = 16, /* h_front_porch */
318 .lower_margin = 1, /* v_front_porch */
319 .vmode = FB_VMODE_NONINTERLACED,
320 .sync = 0,
321 },
322 /* 1152x864p 75hz */
323 {
324 .xres = 1152,
325 .yres = 864,
326 .pixclock = KHZ2PICOS(108000),
327 .hsync_len = 128, /* h_sync_width */
328 .vsync_len = 3, /* v_sync_width */
329 .left_margin = 256, /* h_back_porch */
330 .upper_margin = 32, /* v_back_porch */
331 .right_margin = 64, /* h_front_porch */
332 .lower_margin = 1, /* v_front_porch */
333 .vmode = FB_VMODE_NONINTERLACED,
334 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
335 },
336 /* 1280x800p 60hz */
337 {
338 .xres = 1280,
339 .yres = 800,
340 .pixclock = KHZ2PICOS(83460),
341 .hsync_len = 136, /* h_sync_width */
342 .vsync_len = 3, /* v_sync_width */
343 .left_margin = 200, /* h_back_porch */
344 .upper_margin = 24, /* v_back_porch */
345 .right_margin = 64, /* h_front_porch */
346 .lower_margin = 1, /* v_front_porch */
347 .vmode = FB_VMODE_NONINTERLACED,
348 .sync = FB_SYNC_VERT_HIGH_ACT,
349 },
350 /* 1280x960p 60hz */
351 {
352 .xres = 1280,
353 .yres = 960,
354 .pixclock = KHZ2PICOS(108000),
355 .hsync_len = 136, /* h_sync_width */
356 .vsync_len = 3, /* v_sync_width */
357 .left_margin = 216, /* h_back_porch */
358 .upper_margin = 30, /* v_back_porch */
359 .right_margin = 80, /* h_front_porch */
360 .lower_margin = 1, /* v_front_porch */
361 .vmode = FB_VMODE_NONINTERLACED,
362 .sync = FB_SYNC_VERT_HIGH_ACT,
363 },
364 /* 1280x1024p 60hz */
365 {
366 .xres = 1280,
367 .yres = 1024,
368 .pixclock = KHZ2PICOS(108000),
369 .hsync_len = 112, /* h_sync_width */
370 .vsync_len = 3, /* v_sync_width */
371 .left_margin = 248, /* h_back_porch */
372 .upper_margin = 38, /* v_back_porch */
373 .right_margin = 48, /* h_front_porch */
374 .lower_margin = 1, /* v_front_porch */
375 .vmode = FB_VMODE_NONINTERLACED,
376 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
377 },
378 /* 1280x1024p 75hz */
379 {
380 .xres = 1280,
381 .yres = 1024,
382 .pixclock = KHZ2PICOS(135000),
383 .hsync_len = 144, /* h_sync_width */
384 .vsync_len = 3, /* v_sync_width */
385 .left_margin = 248, /* h_back_porch */
386 .upper_margin = 38, /* v_back_porch */
387 .right_margin = 16, /* h_front_porch */
388 .lower_margin = 1, /* v_front_porch */
389 .vmode = FB_VMODE_NONINTERLACED,
390 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
391 },
392 /* 1368x768p 60hz */
393 {
394 .xres = 1368,
395 .yres = 768,
396 .pixclock = KHZ2PICOS(85860),
397 .hsync_len = 144, /* h_sync_width */
398 .vsync_len = 3, /* v_sync_width */
399 .left_margin = 216, /* h_back_porch */
400 .upper_margin = 23, /* v_back_porch */
401 .right_margin = 72, /* h_front_porch */
402 .lower_margin = 1, /* v_front_porch */
403 .vmode = FB_VMODE_NONINTERLACED,
404 .sync = FB_SYNC_VERT_HIGH_ACT,
405 },
406 /* 1440x900p 60hz */
407 {
408 .xres = 1440,
409 .yres = 900,
410 .pixclock = KHZ2PICOS(106470),
411 .hsync_len = 152, /* h_sync_width */
412 .vsync_len = 3, /* v_sync_width */
413 .left_margin = 232, /* h_back_porch */
414 .upper_margin = 28, /* v_back_porch */
415 .right_margin = 80, /* h_front_porch */
416 .lower_margin = 1, /* v_front_porch */
417 .vmode = FB_VMODE_NONINTERLACED,
418 .sync = FB_SYNC_VERT_HIGH_ACT,
419 },
420 /* 1600x1200p 60hz */
421 {
422 .xres = 1600,
423 .yres = 1200,
424 .pixclock = KHZ2PICOS(162000),
425 .hsync_len = 192, /* h_sync_width */
426 .vsync_len = 3, /* v_sync_width */
427 .left_margin = 304, /* h_back_porch */
428 .upper_margin = 46, /* v_back_porch */
429 .right_margin = 64, /* h_front_porch */
430 .lower_margin = 1, /* v_front_porch */
431 .vmode = FB_VMODE_NONINTERLACED,
432 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
433 },
434 /* 1600x1200p 75hz */
435 {
436 .xres = 1600,
437 .yres = 1200,
438 .pixclock = KHZ2PICOS(202500),
439 .hsync_len = 192, /* h_sync_width */
440 .vsync_len = 3, /* v_sync_width */
441 .left_margin = 304, /* h_back_porch */
442 .upper_margin = 46, /* v_back_porch */
443 .right_margin = 64, /* h_front_porch */
444 .lower_margin = 1, /* v_front_porch */
445 .vmode = FB_VMODE_NONINTERLACED,
446 .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
447 },
448 /* 1680x1050p 59.94/60hz */
449 {
450 .xres = 1680,
451 .yres = 1050,
452 .pixclock = KHZ2PICOS(147140),
453 .hsync_len = 184, /* h_sync_width */
454 .vsync_len = 3, /* v_sync_width */
455 .left_margin = 288, /* h_back_porch */
456 .upper_margin = 33, /* v_back_porch */
457 .right_margin = 104, /* h_front_porch */
458 .lower_margin = 1, /* v_front_porch */
459 .vmode = FB_VMODE_NONINTERLACED,
460 .sync = FB_SYNC_VERT_HIGH_ACT,
461 },
462};
463
464/* CVT timing representation of VESA modes*/
465const struct fb_videomode tegra_dc_hdmi_supported_cvt_modes[] = {
466
467 /* 640x480p 60hz */
468 {
469 .refresh = 60,
470 .xres = 640,
471 .yres = 480,
472 .pixclock = KHZ2PICOS(23750),
473 .hsync_len = 64, /* h_sync_width */
474 .vsync_len = 4, /* v_sync_width */
475 .left_margin = 80, /* h_back_porch */
476 .upper_margin = 17, /* v_back_porch */
477 .right_margin = 16, /* h_front_porch */
478 .lower_margin = 3, /* v_front_porch */
479 .vmode = FB_VMODE_NONINTERLACED,
480 .sync = FB_SYNC_VERT_HIGH_ACT,
481 },
482 /* 640x480p 75hz */
483 {
484 .refresh = 75,
485 .xres = 640,
486 .yres = 480,
487 .pixclock = KHZ2PICOS(30750),
488 .hsync_len = 64, /* h_sync_width */
489 .vsync_len = 4, /* v_sync_width */
490 .left_margin = 88, /* h_back_porch */
491 .upper_margin = 21, /* v_back_porch */
492 .right_margin = 24, /* h_front_porch */
493 .lower_margin = 3, /* v_front_porch */
494 .vmode = FB_VMODE_NONINTERLACED,
495 .sync = FB_SYNC_VERT_HIGH_ACT,
496 },
497 /* 720x400p 59hz */
498 {
499 .refresh = 59,
500 .xres = 720,
501 .yres = 400,
502 .pixclock = KHZ2PICOS(22000),
503 .hsync_len = 64, /* h_sync_width */
504 .vsync_len = 10, /* v_sync_width */
505 .left_margin = 88, /* h_back_porch */
506 .upper_margin = 14, /* v_back_porch */
507 .right_margin = 24, /* h_front_porch */
508 .lower_margin = 3, /* v_front_porch */
509 .vmode = FB_VMODE_NONINTERLACED,
510 .sync = FB_SYNC_VERT_HIGH_ACT,
511 },
512 /* 800x600p 60hz */
513 {
514 .refresh = 60,
515 .xres = 800,
516 .yres = 600,
517 .pixclock = KHZ2PICOS(38250),
518 .hsync_len = 80, /* h_sync_width */
519 .vsync_len = 4, /* v_sync_width */
520 .left_margin = 112, /* h_back_porch */
521 .upper_margin = 21, /* v_back_porch */
522 .right_margin = 32, /* h_front_porch */
523 .lower_margin = 3, /* v_front_porch */
524 .vmode = FB_VMODE_NONINTERLACED,
525 .sync = FB_SYNC_VERT_HIGH_ACT,
526 },
527 /* 800x600p 75hz */
528 {
529 .refresh = 75,
530 .xres = 800,
531 .yres = 600,
532 .pixclock = KHZ2PICOS(49000),
533 .hsync_len = 80, /* h_sync_width */
534 .vsync_len = 4, /* v_sync_width */
535 .left_margin = 120, /* h_back_porch */
536 .upper_margin = 26, /* v_back_porch */
537 .right_margin = 40, /* h_front_porch */
538 .lower_margin = 3, /* v_front_porch */
539 .vmode = FB_VMODE_NONINTERLACED,
540 .sync = FB_SYNC_VERT_HIGH_ACT,
541 },
542 /* 1024x768p 60hz */
543 {
544 .refresh = 60,
545 .xres = 1024,
546 .yres = 768,
547 .pixclock = KHZ2PICOS(63500),
548 .hsync_len = 104, /* h_sync_width */
549 .vsync_len = 4, /* v_sync_width */
550 .left_margin = 152, /* h_back_porch */
551 .upper_margin = 27, /* v_back_porch */
552 .right_margin = 48, /* h_front_porch */
553 .lower_margin = 3, /* v_front_porch */
554 .vmode = FB_VMODE_NONINTERLACED,
555 .sync = FB_SYNC_VERT_HIGH_ACT,
556 },
557 /* 1024x768p 75hz */
558 {
559 .refresh = 75,
560 .xres = 1024,
561 .yres = 768,
562 .pixclock = KHZ2PICOS(82000),
563 .hsync_len = 104, /* h_sync_width */
564 .vsync_len = 4, /* v_sync_width */
565 .left_margin = 168, /* h_back_porch */
566 .upper_margin = 34, /* v_back_porch */
567 .right_margin = 64, /* h_front_porch */
568 .lower_margin = 3, /* v_front_porch */
569 .vmode = FB_VMODE_NONINTERLACED,
570 .sync = FB_SYNC_VERT_HIGH_ACT,
571 },
572 /* 1152x864p 75hz */
573 {
574 .refresh = 75,
575 .xres = 1152,
576 .yres = 864,
577 .pixclock = KHZ2PICOS(104500),
578 .hsync_len = 120, /* h_sync_width */
579 .vsync_len = 10, /* v_sync_width */
580 .left_margin = 192, /* h_back_porch */
581 .upper_margin = 38, /* v_back_porch */
582 .right_margin = 72, /* h_front_porch */
583 .lower_margin = 3, /* v_front_porch */
584 .vmode = FB_VMODE_NONINTERLACED,
585 .sync = FB_SYNC_VERT_HIGH_ACT,
586 },
587 /* 1280x800p 60hz */
588 {
589 .refresh = 60,
590 .xres = 1280,
591 .yres = 800,
592 .pixclock = KHZ2PICOS(83500),
593 .hsync_len = 128, /* h_sync_width */
594 .vsync_len = 6, /* v_sync_width */
595 .left_margin = 200, /* h_back_porch */
596 .upper_margin = 28, /* v_back_porch */
597 .right_margin = 72, /* h_front_porch */
598 .lower_margin = 3, /* v_front_porch */
599 .vmode = FB_VMODE_NONINTERLACED,
600 .sync = FB_SYNC_VERT_HIGH_ACT,
601 },
602 /* 1280x960p 60hz */
603 {
604 .refresh = 60,
605 .xres = 1280,
606 .yres = 960,
607 .pixclock = KHZ2PICOS(101250),
608 .hsync_len = 128, /* h_sync_width */
609 .vsync_len = 4, /* v_sync_width */
610 .left_margin = 208, /* h_back_porch */
611 .upper_margin = 33, /* v_back_porch */
612 .right_margin = 80, /* h_front_porch */
613 .lower_margin = 3, /* v_front_porch */
614 .vmode = FB_VMODE_NONINTERLACED,
615 .sync = FB_SYNC_VERT_HIGH_ACT,
616 },
617 /* 1280x1024p 60hz */
618 {
619 .refresh = 60,
620 .xres = 1280,
621 .yres = 1024,
622 .pixclock = KHZ2PICOS(109000),
623 .hsync_len = 136, /* h_sync_width */
624 .vsync_len = 7, /* v_sync_width */
625 .left_margin = 216, /* h_back_porch */
626 .upper_margin = 36, /* v_back_porch */
627 .right_margin = 80, /* h_front_porch */
628 .lower_margin = 3, /* v_front_porch */
629 .vmode = FB_VMODE_NONINTERLACED,
630 .sync = FB_SYNC_VERT_HIGH_ACT,
631 },
632
633 /* 1280x1024p 75hz */
634 {
635 .refresh = 75,
636 .xres = 1280,
637 .yres = 1024,
638 .pixclock = KHZ2PICOS(138750),
639 .hsync_len = 136, /* h_sync_width */
640 .vsync_len = 7, /* v_sync_width */
641 .left_margin = 224, /* h_back_porch */
642 .upper_margin = 45, /* v_back_porch */
643 .right_margin = 88, /* h_front_porch */
644 .lower_margin = 3, /* v_front_porch */
645 .vmode = FB_VMODE_NONINTERLACED,
646 .sync = FB_SYNC_VERT_HIGH_ACT,
647 },
648 /* 1368x768p 60hz */
649 {
650 .refresh = 60,
651 .xres = 1368,
652 .yres = 768,
653 .pixclock = KHZ2PICOS(85250),
654 .hsync_len = 136, /* h_sync_width */
655 .vsync_len = 10, /* v_sync_width */
656 .left_margin = 208, /* h_back_porch */
657 .upper_margin = 27, /* v_back_porch */
658 .right_margin = 72, /* h_front_porch */
659 .lower_margin = 3, /* v_front_porch */
660 .vmode = FB_VMODE_NONINTERLACED,
661 .sync = FB_SYNC_VERT_HIGH_ACT,
662 },
663 /* 1440x900p 60hz */
664 {
665 .refresh = 60,
666 .xres = 1440,
667 .yres = 900,
668 .pixclock = KHZ2PICOS(106500),
669 .hsync_len = 152, /* h_sync_width */
670 .vsync_len = 6, /* v_sync_width */
671 .left_margin = 232, /* h_back_porch */
672 .upper_margin = 31, /* v_back_porch */
673 .right_margin = 80, /* h_front_porch */
674 .lower_margin = 3, /* v_front_porch */
675 .vmode = FB_VMODE_NONINTERLACED,
676 .sync = FB_SYNC_VERT_HIGH_ACT,
677 },
678 /* 1600x1200p 60hz */
679 {
680 .refresh = 60,
681 .xres = 1600,
682 .yres = 1200,
683 .pixclock = KHZ2PICOS(161000),
684 .hsync_len = 168, /* h_sync_width */
685 .vsync_len = 4, /* v_sync_width */
686 .left_margin = 280, /* h_back_porch */
687 .upper_margin = 42, /* v_back_porch */
688 .right_margin = 112, /* h_front_porch */
689 .lower_margin = 3, /* v_front_porch */
690 .vmode = FB_VMODE_NONINTERLACED,
691 .sync = FB_SYNC_VERT_HIGH_ACT,
692 },
693 /* 1600x1200p 75hz */
694 {
695 .refresh = 75,
696 .xres = 1600,
697 .yres = 1200,
698 .pixclock = KHZ2PICOS(204750),
699 .hsync_len = 168, /* h_sync_width */
700 .vsync_len = 4, /* v_sync_width */
701 .left_margin = 288, /* h_back_porch */
702 .upper_margin = 52, /* v_back_porch */
703 .right_margin = 120, /* h_front_porch */
704 .lower_margin = 3, /* v_front_porch */
705 .vmode = FB_VMODE_NONINTERLACED,
706 .sync = FB_SYNC_VERT_HIGH_ACT,
707 },
708 /* 1680x1050p 59.94/60hz */
709 {
710 .refresh = 60,
711 .xres = 1680,
712 .yres = 1050,
713 .pixclock = KHZ2PICOS(140000),
714 .hsync_len = 168, /* h_sync_width */
715 .vsync_len = 10, /* v_sync_width */
716 .left_margin = 272, /* h_back_porch */
717 .upper_margin = 36, /* v_back_porch */
718 .right_margin = 104, /* h_front_porch */
719 .lower_margin = 3, /* v_front_porch */
720 .vmode = FB_VMODE_NONINTERLACED,
721 .sync = FB_SYNC_VERT_HIGH_ACT,
722 },
723};
724
725/* table of electrical settings, must be in acending order. */
726struct tdms_config {
727 int pclk;
728 u32 pll0;
729 u32 pll1;
730 u32 pe_current; /* pre-emphasis */
731 u32 drive_current;
732};
733
734#ifndef CONFIG_ARCH_TEGRA_2x_SOC
735const struct tdms_config tdms_config[] = {
736 { /* 480p modes */
737 .pclk = 27000000,
738 .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL |
739 SOR_PLL_VCOCAP(0) | SOR_PLL_TX_REG_LOAD(0),
740 .pll1 = SOR_PLL_TMDS_TERM_ENABLE,
741 .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) |
742 PE_CURRENT1(PE_CURRENT_0_0_mA) |
743 PE_CURRENT2(PE_CURRENT_0_0_mA) |
744 PE_CURRENT3(PE_CURRENT_0_0_mA),
745 .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) |
746 DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) |
747 DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) |
748 DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA),
749 },
750 { /* 720p modes */
751 .pclk = 74250000,
752 .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL |
753 SOR_PLL_VCOCAP(1) | SOR_PLL_TX_REG_LOAD(0),
754 .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
755 .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) |
756 PE_CURRENT1(PE_CURRENT_5_0_mA) |
757 PE_CURRENT2(PE_CURRENT_5_0_mA) |
758 PE_CURRENT3(PE_CURRENT_5_0_mA),
759 .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) |
760 DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) |
761 DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) |
762 DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA),
763 },
764 { /* 1080p modes */
765 .pclk = INT_MAX,
766 .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL |
767 SOR_PLL_VCOCAP(3) | SOR_PLL_TX_REG_LOAD(0),
768 .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
769 .pe_current = PE_CURRENT0(PE_CURRENT_5_0_mA) |
770 PE_CURRENT1(PE_CURRENT_5_0_mA) |
771 PE_CURRENT2(PE_CURRENT_5_0_mA) |
772 PE_CURRENT3(PE_CURRENT_5_0_mA),
773 .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_5_250_mA) |
774 DRIVE_CURRENT_LANE1(DRIVE_CURRENT_5_250_mA) |
775 DRIVE_CURRENT_LANE2(DRIVE_CURRENT_5_250_mA) |
776 DRIVE_CURRENT_LANE3(DRIVE_CURRENT_5_250_mA),
777 },
778};
779#else /* CONFIG_ARCH_TEGRA_2x_SOC */
780const struct tdms_config tdms_config[] = {
781 { /* 480p modes */
782 .pclk = 27000000,
783 .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL |
784 SOR_PLL_VCOCAP(0) | SOR_PLL_TX_REG_LOAD(3),
785 .pll1 = SOR_PLL_TMDS_TERM_ENABLE,
786 .pe_current = PE_CURRENT0(PE_CURRENT_0_0_mA) |
787 PE_CURRENT1(PE_CURRENT_0_0_mA) |
788 PE_CURRENT2(PE_CURRENT_0_0_mA) |
789 PE_CURRENT3(PE_CURRENT_0_0_mA),
790 .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) |
791 DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
792 DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
793 DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
794 },
795 { /* 720p modes */
796 .pclk = 74250000,
797 .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL |
798 SOR_PLL_VCOCAP(1) | SOR_PLL_TX_REG_LOAD(3),
799 .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
800 .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) |
801 PE_CURRENT1(PE_CURRENT_6_0_mA) |
802 PE_CURRENT2(PE_CURRENT_6_0_mA) |
803 PE_CURRENT3(PE_CURRENT_6_0_mA),
804 .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) |
805 DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
806 DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
807 DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
808 },
809 { /* 1080p modes */
810 .pclk = INT_MAX,
811 .pll0 = SOR_PLL_BG_V17_S(3) | SOR_PLL_ICHPMP(1) | SOR_PLL_RESISTORSEL |
812 SOR_PLL_VCOCAP(1) | SOR_PLL_TX_REG_LOAD(3),
813 .pll1 = SOR_PLL_TMDS_TERM_ENABLE | SOR_PLL_PE_EN,
814 .pe_current = PE_CURRENT0(PE_CURRENT_6_0_mA) |
815 PE_CURRENT1(PE_CURRENT_6_0_mA) |
816 PE_CURRENT2(PE_CURRENT_6_0_mA) |
817 PE_CURRENT3(PE_CURRENT_6_0_mA),
818 .drive_current = DRIVE_CURRENT_LANE0(DRIVE_CURRENT_7_125_mA) |
819 DRIVE_CURRENT_LANE1(DRIVE_CURRENT_7_125_mA) |
820 DRIVE_CURRENT_LANE2(DRIVE_CURRENT_7_125_mA) |
821 DRIVE_CURRENT_LANE3(DRIVE_CURRENT_7_125_mA),
822 },
823};
824#endif
825
826struct tegra_hdmi_audio_config {
827 unsigned pix_clock;
828 unsigned n;
829 unsigned cts;
830 unsigned aval;
831};
832
833
834const struct tegra_hdmi_audio_config tegra_hdmi_audio_32k[] = {
835 {25200000, 4096, 25200, 24000},
836 {27000000, 4096, 27000, 24000},
837 {74250000, 4096, 74250, 24000},
838 {148500000, 4096, 148500, 24000},
839 {0, 0, 0},
840};
841
842const struct tegra_hdmi_audio_config tegra_hdmi_audio_44_1k[] = {
843 {25200000, 5880, 26250, 25000},
844 {27000000, 5880, 28125, 25000},
845 {74250000, 4704, 61875, 20000},
846 {148500000, 4704, 123750, 20000},
847 {0, 0, 0},
848};
849
850const struct tegra_hdmi_audio_config tegra_hdmi_audio_48k[] = {
851 {25200000, 6144, 25200, 24000},
852 {27000000, 6144, 27000, 24000},
853 {74250000, 6144, 74250, 24000},
854 {148500000, 6144, 148500, 24000},
855 {0, 0, 0},
856};
857
858const struct tegra_hdmi_audio_config tegra_hdmi_audio_88_2k[] = {
859 {25200000, 11760, 26250, 25000},
860 {27000000, 11760, 28125, 25000},
861 {74250000, 9408, 61875, 20000},
862 {148500000, 9408, 123750, 20000},
863 {0, 0, 0},
864};
865
866const struct tegra_hdmi_audio_config tegra_hdmi_audio_96k[] = {
867 {25200000, 12288, 25200, 24000},
868 {27000000, 12288, 27000, 24000},
869 {74250000, 12288, 74250, 24000},
870 {148500000, 12288, 148500, 24000},
871 {0, 0, 0},
872};
873
874const struct tegra_hdmi_audio_config tegra_hdmi_audio_176_4k[] = {
875 {25200000, 23520, 26250, 25000},
876 {27000000, 23520, 28125, 25000},
877 {74250000, 18816, 61875, 20000},
878 {148500000, 18816, 123750, 20000},
879 {0, 0, 0},
880};
881
882const struct tegra_hdmi_audio_config tegra_hdmi_audio_192k[] = {
883 {25200000, 24576, 25200, 24000},
884 {27000000, 24576, 27000, 24000},
885 {74250000, 24576, 74250, 24000},
886 {148500000, 24576, 148500, 24000},
887 {0, 0, 0},
888};
889
890static const struct tegra_hdmi_audio_config
891*tegra_hdmi_get_audio_config(unsigned audio_freq, unsigned pix_clock)
892{
893 const struct tegra_hdmi_audio_config *table;
894
895 switch (audio_freq) {
896 case AUDIO_FREQ_32K:
897 table = tegra_hdmi_audio_32k;
898 break;
899 case AUDIO_FREQ_44_1K:
900 table = tegra_hdmi_audio_44_1k;
901 break;
902 case AUDIO_FREQ_48K:
903 table = tegra_hdmi_audio_48k;
904 break;
905 case AUDIO_FREQ_88_2K:
906 table = tegra_hdmi_audio_88_2k;
907 break;
908 case AUDIO_FREQ_96K:
909 table = tegra_hdmi_audio_96k;
910 break;
911 case AUDIO_FREQ_176_4K:
912 table = tegra_hdmi_audio_176_4k;
913 break;
914 case AUDIO_FREQ_192K:
915 table = tegra_hdmi_audio_192k;
916 break;
917 default:
918 return NULL;
919 }
920
921 while (table->pix_clock) {
922 if (table->pix_clock == pix_clock)
923 return table;
924 table++;
925 }
926
927 return NULL;
928}
929
930
931unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
932 unsigned long reg)
933{
934 return readl(hdmi->base + reg * 4);
935}
936
937void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
938 unsigned long val, unsigned long reg)
939{
940 writel(val, hdmi->base + reg * 4);
941}
942
943static inline void tegra_hdmi_clrsetbits(struct tegra_dc_hdmi_data *hdmi,
944 unsigned long reg, unsigned long clr,
945 unsigned long set)
946{
947 unsigned long val = tegra_hdmi_readl(hdmi, reg);
948 val &= ~clr;
949 val |= set;
950 tegra_hdmi_writel(hdmi, val, reg);
951}
952
953#ifdef CONFIG_DEBUG_FS
954static int dbg_hdmi_show(struct seq_file *s, void *unused)
955{
956 struct tegra_dc_hdmi_data *hdmi = s->private;
957
958#define DUMP_REG(a) do { \
959 seq_printf(s, "%-32s\t%03x\t%08lx\n", \
960 #a, a, tegra_hdmi_readl(hdmi, a)); \
961 } while (0)
962
963 tegra_dc_io_start(hdmi->dc);
964 clk_enable(hdmi->clk);
965
966 DUMP_REG(HDMI_CTXSW);
967 DUMP_REG(HDMI_NV_PDISP_SOR_STATE0);
968 DUMP_REG(HDMI_NV_PDISP_SOR_STATE1);
969 DUMP_REG(HDMI_NV_PDISP_SOR_STATE2);
970 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_MSB);
971 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AN_LSB);
972 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_MSB);
973 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CN_LSB);
974 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_MSB);
975 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_AKSV_LSB);
976 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_MSB);
977 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_BKSV_LSB);
978 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_MSB);
979 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CKSV_LSB);
980 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_MSB);
981 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_DKSV_LSB);
982 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CTRL);
983 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CMODE);
984 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB);
985 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB);
986 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB);
987 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2);
988 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1);
989 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_RI);
990 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_MSB);
991 DUMP_REG(HDMI_NV_PDISP_RG_HDCP_CS_LSB);
992 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU0);
993 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0);
994 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU1);
995 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_EMU2);
996 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL);
997 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS);
998 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER);
999 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW);
1000 DUMP_REG(HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH);
1001 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL);
1002 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS);
1003 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER);
1004 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW);
1005 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH);
1006 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW);
1007 DUMP_REG(HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH);
1008 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
1009 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_STATUS);
1010 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_HEADER);
1011 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW);
1012 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH);
1013 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW);
1014 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH);
1015 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW);
1016 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH);
1017 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW);
1018 DUMP_REG(HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH);
1019 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_CTRL);
1020 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW);
1021 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH);
1022 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW);
1023 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH);
1024 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW);
1025 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH);
1026 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW);
1027 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH);
1028 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW);
1029 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH);
1030 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW);
1031 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH);
1032 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW);
1033 DUMP_REG(HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH);
1034 DUMP_REG(HDMI_NV_PDISP_HDMI_CTRL);
1035 DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT);
1036 DUMP_REG(HDMI_NV_PDISP_HDMI_VSYNC_WINDOW);
1037 DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_CTRL);
1038 DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_STATUS);
1039 DUMP_REG(HDMI_NV_PDISP_HDMI_GCP_SUBPACK);
1040 DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1);
1041 DUMP_REG(HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2);
1042 DUMP_REG(HDMI_NV_PDISP_HDMI_EMU0);
1043 DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1);
1044 DUMP_REG(HDMI_NV_PDISP_HDMI_EMU1_RDATA);
1045 DUMP_REG(HDMI_NV_PDISP_HDMI_SPARE);
1046 DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1);
1047 DUMP_REG(HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2);
1048 DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_CTRL);
1049 DUMP_REG(HDMI_NV_PDISP_SOR_CAP);
1050 DUMP_REG(HDMI_NV_PDISP_SOR_PWR);
1051 DUMP_REG(HDMI_NV_PDISP_SOR_TEST);
1052 DUMP_REG(HDMI_NV_PDISP_SOR_PLL0);
1053 DUMP_REG(HDMI_NV_PDISP_SOR_PLL1);
1054 DUMP_REG(HDMI_NV_PDISP_SOR_PLL2);
1055 DUMP_REG(HDMI_NV_PDISP_SOR_CSTM);
1056 DUMP_REG(HDMI_NV_PDISP_SOR_LVDS);
1057 DUMP_REG(HDMI_NV_PDISP_SOR_CRCA);
1058 DUMP_REG(HDMI_NV_PDISP_SOR_CRCB);
1059 DUMP_REG(HDMI_NV_PDISP_SOR_BLANK);
1060 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_CTL);
1061 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST0);
1062 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST1);
1063 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST2);
1064 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST3);
1065 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST4);
1066 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST5);
1067 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST6);
1068 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST7);
1069 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST8);
1070 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INST9);
1071 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTA);
1072 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTB);
1073 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTC);
1074 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTD);
1075 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTE);
1076 DUMP_REG(HDMI_NV_PDISP_SOR_SEQ_INSTF);
1077 DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA0);
1078 DUMP_REG(HDMI_NV_PDISP_SOR_VCRCA1);
1079 DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA0);
1080 DUMP_REG(HDMI_NV_PDISP_SOR_CCRCA1);
1081 DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA0);
1082 DUMP_REG(HDMI_NV_PDISP_SOR_EDATAA1);
1083 DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA0);
1084 DUMP_REG(HDMI_NV_PDISP_SOR_COUNTA1);
1085 DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA0);
1086 DUMP_REG(HDMI_NV_PDISP_SOR_DEBUGA1);
1087 DUMP_REG(HDMI_NV_PDISP_SOR_TRIG);
1088 DUMP_REG(HDMI_NV_PDISP_SOR_MSCHECK);
1089 DUMP_REG(HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT);
1090 DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG0);
1091 DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG1);
1092 DUMP_REG(HDMI_NV_PDISP_AUDIO_DEBUG2);
1093 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(0));
1094 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(1));
1095 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(2));
1096 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(3));
1097 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(4));
1098 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(5));
1099 DUMP_REG(HDMI_NV_PDISP_AUDIO_FS(6));
1100 DUMP_REG(HDMI_NV_PDISP_AUDIO_PULSE_WIDTH);
1101 DUMP_REG(HDMI_NV_PDISP_AUDIO_THRESHOLD);
1102 DUMP_REG(HDMI_NV_PDISP_AUDIO_CNTRL0);
1103 DUMP_REG(HDMI_NV_PDISP_AUDIO_N);
1104 DUMP_REG(HDMI_NV_PDISP_HDCPRIF_ROM_TIMING);
1105 DUMP_REG(HDMI_NV_PDISP_SOR_REFCLK);
1106 DUMP_REG(HDMI_NV_PDISP_CRC_CONTROL);
1107 DUMP_REG(HDMI_NV_PDISP_INPUT_CONTROL);
1108 DUMP_REG(HDMI_NV_PDISP_SCRATCH);
1109 DUMP_REG(HDMI_NV_PDISP_PE_CURRENT);
1110 DUMP_REG(HDMI_NV_PDISP_KEY_CTRL);
1111 DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG0);
1112 DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG1);
1113 DUMP_REG(HDMI_NV_PDISP_KEY_DEBUG2);
1114 DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_0);
1115 DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_1);
1116 DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_2);
1117 DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_3);
1118 DUMP_REG(HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG);
1119 DUMP_REG(HDMI_NV_PDISP_KEY_SKEY_INDEX);
1120#undef DUMP_REG
1121
1122 clk_disable(hdmi->clk);
1123 tegra_dc_io_end(hdmi->dc);
1124
1125 return 0;
1126}
1127
1128static int dbg_hdmi_open(struct inode *inode, struct file *file)
1129{
1130 return single_open(file, dbg_hdmi_show, inode->i_private);
1131}
1132
1133static const struct file_operations dbg_fops = {
1134 .open = dbg_hdmi_open,
1135 .read = seq_read,
1136 .llseek = seq_lseek,
1137 .release = single_release,
1138};
1139
1140static struct dentry *hdmidir;
1141
1142static void tegra_dc_hdmi_debug_create(struct tegra_dc_hdmi_data *hdmi)
1143{
1144 struct dentry *retval;
1145
1146 hdmidir = debugfs_create_dir("tegra_hdmi", NULL);
1147 if (!hdmidir)
1148 return;
1149 retval = debugfs_create_file("regs", S_IRUGO, hdmidir, hdmi,
1150 &dbg_fops);
1151 if (!retval)
1152 goto free_out;
1153 return;
1154free_out:
1155 debugfs_remove_recursive(hdmidir);
1156 hdmidir = NULL;
1157 return;
1158}
1159#else
1160static inline void tegra_dc_hdmi_debug_create(struct tegra_dc_hdmi_data *hdmi)
1161{ }
1162#endif
1163
1164#define PIXCLOCK_TOLERANCE 200
1165
1166static int tegra_dc_calc_clock_per_frame(const struct fb_videomode *mode)
1167{
1168 return (mode->left_margin + mode->xres +
1169 mode->right_margin + mode->hsync_len) *
1170 (mode->upper_margin + mode->yres +
1171 mode->lower_margin + mode->vsync_len);
1172}
1173static bool tegra_dc_hdmi_mode_equal(const struct fb_videomode *mode1,
1174 const struct fb_videomode *mode2)
1175{
1176 int clock_per_frame1 = tegra_dc_calc_clock_per_frame(mode1);
1177 int clock_per_frame2 = tegra_dc_calc_clock_per_frame(mode2);
1178
1179 /* allows up to 1Hz of pixclock difference */
1180 return (clock_per_frame1 == clock_per_frame2 &&
1181 mode1->xres == mode2->xres &&
1182 mode1->yres == mode2->yres &&
1183 mode1->vmode == mode2->vmode &&
1184 (mode1->pixclock == mode2->pixclock ||
1185 (abs(PICOS2KHZ(mode1->pixclock) -
1186 PICOS2KHZ(mode2->pixclock)) *
1187 1000 / clock_per_frame1 <= 1)));
1188}
1189
1190static bool tegra_dc_hdmi_valid_pixclock(const struct tegra_dc *dc,
1191 const struct fb_videomode *mode)
1192{
1193 unsigned max_pixclock = tegra_dc_get_out_max_pixclock(dc);
1194 if (max_pixclock) {
1195 /* this might look counter-intuitive,
1196 * but pixclock's unit is picos(not Khz)
1197 */
1198 return mode->pixclock >= max_pixclock;
1199 } else {
1200 return true;
1201 }
1202}
1203
1204static bool tegra_dc_cvt_mode_equal(const struct fb_videomode *mode1,
1205 const struct fb_videomode *mode2)
1206{
1207 return (mode1->xres == mode2->xres &&
1208 mode1->yres == mode2->yres &&
1209 mode1->refresh == mode2->refresh &&
1210 mode1->vmode == mode2->vmode);
1211}
1212
1213static bool tegra_dc_reload_mode(struct fb_videomode *mode)
1214{
1215 int i = 0;
1216 for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_cvt_modes); i++) {
1217 const struct fb_videomode *cvt_mode
1218 = &tegra_dc_hdmi_supported_cvt_modes[i];
1219 if (tegra_dc_cvt_mode_equal(cvt_mode, mode)) {
1220 memcpy(mode, cvt_mode, sizeof(*mode));
1221 return true;
1222 }
1223 }
1224 return false;
1225}
1226
1227
1228static bool tegra_dc_hdmi_mode_filter(const struct tegra_dc *dc,
1229 struct fb_videomode *mode)
1230{
1231 int i;
1232 int clock_per_frame;
1233
1234 if (!mode->pixclock)
1235 return false;
1236
1237#ifdef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
1238 if (PICOS2KHZ(mode->pixclock) > 74250)
1239 return false;
1240#endif
1241
1242 for (i = 0; i < ARRAY_SIZE(tegra_dc_hdmi_supported_modes); i++) {
1243 const struct fb_videomode *supported_mode
1244 = &tegra_dc_hdmi_supported_modes[i];
1245 if (tegra_dc_hdmi_mode_equal(supported_mode, mode) &&
1246 tegra_dc_hdmi_valid_pixclock(dc, supported_mode)) {
1247 if (mode->lower_margin == 1) {
1248 /* This might be the case for HDMI<->DVI
1249 * where std VESA representation will not
1250 * pass constraint V_FRONT_PORCH >=
1251 * V_REF_TO_SYNC + 1.So reload mode in
1252 * CVT timing standards.
1253 */
1254 if (!tegra_dc_reload_mode(mode))
1255 return false;
1256 }
1257 else
1258 memcpy(mode, supported_mode, sizeof(*mode));
1259
1260 mode->flag = FB_MODE_IS_DETAILED;
1261 clock_per_frame = tegra_dc_calc_clock_per_frame(mode);
1262 mode->refresh = (PICOS2KHZ(mode->pixclock) * 1000)
1263 / clock_per_frame;
1264 return true;
1265 }
1266 }
1267
1268 return false;
1269}
1270
1271
1272static bool tegra_dc_hdmi_hpd(struct tegra_dc *dc)
1273{
1274 int sense;
1275 int level;
1276
1277 level = gpio_get_value(dc->out->hotplug_gpio);
1278
1279 sense = dc->out->flags & TEGRA_DC_OUT_HOTPLUG_MASK;
1280
1281 return (sense == TEGRA_DC_OUT_HOTPLUG_HIGH && level) ||
1282 (sense == TEGRA_DC_OUT_HOTPLUG_LOW && !level);
1283}
1284
1285
1286void tegra_dc_hdmi_detect_config(struct tegra_dc *dc,
1287 struct fb_monspecs *specs)
1288{
1289 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1290
1291 /* monitors like to lie about these but they are still useful for
1292 * detecting aspect ratios
1293 */
1294 dc->out->h_size = specs->max_x * 1000;
1295 dc->out->v_size = specs->max_y * 1000;
1296
1297 hdmi->dvi = !(specs->misc & FB_MISC_HDMI);
1298
1299 tegra_fb_update_monspecs(dc->fb, specs, tegra_dc_hdmi_mode_filter);
1300#ifdef CONFIG_SWITCH
1301 hdmi->hpd_switch.state = 0;
1302 switch_set_state(&hdmi->hpd_switch, 1);
1303#endif
1304 dev_info(&dc->ndev->dev, "display detected\n");
1305
1306 dc->connected = true;
1307 tegra_dc_ext_process_hotplug(dc->ndev->id);
1308}
1309
1310/* This function is used to enable DC1 and HDMI for the purpose of testing. */
1311bool tegra_dc_hdmi_detect_test(struct tegra_dc *dc, unsigned char *edid_ptr)
1312{
1313 int err;
1314 struct fb_monspecs specs;
1315 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1316
1317 if (!hdmi || !edid_ptr) {
1318 dev_err(&dc->ndev->dev, "HDMI test failed to get arguments.\n");
1319 return false;
1320 }
1321
1322 err = tegra_edid_get_monspecs_test(hdmi->edid, &specs, edid_ptr);
1323 if (err < 0) {
1324 dev_err(&dc->ndev->dev, "error reading edid\n");
1325 goto fail;
1326 }
1327
1328 err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld);
1329 if (err < 0) {
1330 dev_err(&dc->ndev->dev, "error populating eld\n");
1331 goto fail;
1332 }
1333 hdmi->eld_retrieved = true;
1334
1335 tegra_dc_hdmi_detect_config(dc, &specs);
1336
1337 return true;
1338
1339fail:
1340 hdmi->eld_retrieved = false;
1341#ifdef CONFIG_SWITCH
1342 switch_set_state(&hdmi->hpd_switch, 0);
1343#endif
1344 tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
1345 return false;
1346}
1347EXPORT_SYMBOL(tegra_dc_hdmi_detect_test);
1348
1349static bool tegra_dc_hdmi_detect(struct tegra_dc *dc)
1350{
1351 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1352 struct fb_monspecs specs;
1353 int err;
1354
1355 if (!tegra_dc_hdmi_hpd(dc))
1356 goto fail;
1357
1358 err = tegra_edid_get_monspecs(hdmi->edid, &specs);
1359 if (err < 0) {
1360 dev_err(&dc->ndev->dev, "error reading edid\n");
1361 goto fail;
1362 }
1363
1364 err = tegra_edid_get_eld(hdmi->edid, &hdmi->eld);
1365 if (err < 0) {
1366 dev_err(&dc->ndev->dev, "error populating eld\n");
1367 goto fail;
1368 }
1369 hdmi->eld_retrieved = true;
1370
1371 tegra_dc_hdmi_detect_config(dc, &specs);
1372
1373 return true;
1374
1375fail:
1376 hdmi->eld_retrieved = false;
1377#ifdef CONFIG_SWITCH
1378 switch_set_state(&hdmi->hpd_switch, 0);
1379#endif
1380 tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
1381 return false;
1382}
1383
1384
1385static void tegra_dc_hdmi_detect_worker(struct work_struct *work)
1386{
1387 struct tegra_dc_hdmi_data *hdmi =
1388 container_of(to_delayed_work(work), struct tegra_dc_hdmi_data, work);
1389 struct tegra_dc *dc = hdmi->dc;
1390
1391 tegra_dc_enable(dc);
1392 msleep(5);
1393 if (!tegra_dc_hdmi_detect(dc)) {
1394 tegra_dc_disable(dc);
1395 tegra_fb_update_monspecs(dc->fb, NULL, NULL);
1396
1397 dc->connected = false;
1398 tegra_dc_ext_process_hotplug(dc->ndev->id);
1399 }
1400}
1401
1402static irqreturn_t tegra_dc_hdmi_irq(int irq, void *ptr)
1403{
1404 struct tegra_dc *dc = ptr;
1405 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1406 unsigned long flags;
1407
1408 spin_lock_irqsave(&hdmi->suspend_lock, flags);
1409 if (!hdmi->suspended) {
1410 __cancel_delayed_work(&hdmi->work);
1411 if (tegra_dc_hdmi_hpd(dc))
1412 queue_delayed_work(system_nrt_wq, &hdmi->work,
1413 msecs_to_jiffies(100));
1414 else
1415 queue_delayed_work(system_nrt_wq, &hdmi->work,
1416 msecs_to_jiffies(30));
1417 }
1418 spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
1419
1420 return IRQ_HANDLED;
1421}
1422
1423static void tegra_dc_hdmi_suspend(struct tegra_dc *dc)
1424{
1425 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1426 unsigned long flags;
1427
1428 tegra_nvhdcp_suspend(hdmi->nvhdcp);
1429 spin_lock_irqsave(&hdmi->suspend_lock, flags);
1430 hdmi->suspended = true;
1431 spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
1432}
1433
1434static void tegra_dc_hdmi_resume(struct tegra_dc *dc)
1435{
1436 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1437 unsigned long flags;
1438
1439 spin_lock_irqsave(&hdmi->suspend_lock, flags);
1440 hdmi->suspended = false;
1441
1442 if (tegra_dc_hdmi_hpd(dc))
1443 queue_delayed_work(system_nrt_wq, &hdmi->work,
1444 msecs_to_jiffies(100));
1445 else
1446 queue_delayed_work(system_nrt_wq, &hdmi->work,
1447 msecs_to_jiffies(30));
1448
1449 spin_unlock_irqrestore(&hdmi->suspend_lock, flags);
1450 tegra_nvhdcp_resume(hdmi->nvhdcp);
1451}
1452
1453static ssize_t underscan_show(struct device *dev,
1454 struct device_attribute *attr, char *buf)
1455{
1456#ifdef CONFIG_SWITCH
1457 struct tegra_dc_hdmi_data *hdmi =
1458 container_of(dev_get_drvdata(dev), struct tegra_dc_hdmi_data, hpd_switch);
1459
1460 if (hdmi->edid)
1461 return sprintf(buf, "%d\n", tegra_edid_underscan_supported(hdmi->edid));
1462 else
1463 return 0;
1464#else
1465 return 0;
1466#endif
1467}
1468
1469static DEVICE_ATTR(underscan, S_IRUGO | S_IWUSR, underscan_show, NULL);
1470
1471static int tegra_dc_hdmi_init(struct tegra_dc *dc)
1472{
1473 struct tegra_dc_hdmi_data *hdmi;
1474 struct resource *res;
1475 struct resource *base_res;
1476 int ret;
1477 void __iomem *base;
1478 struct clk *clk = NULL;
1479 struct clk *disp1_clk = NULL;
1480 struct clk *disp2_clk = NULL;
1481 int err;
1482
1483 hdmi = kzalloc(sizeof(*hdmi), GFP_KERNEL);
1484 if (!hdmi)
1485 return -ENOMEM;
1486
1487 res = nvhost_get_resource_byname(dc->ndev, IORESOURCE_MEM, "hdmi_regs");
1488 if (!res) {
1489 dev_err(&dc->ndev->dev, "hdmi: no mem resource\n");
1490 err = -ENOENT;
1491 goto err_free_hdmi;
1492 }
1493
1494 base_res = request_mem_region(res->start, resource_size(res), dc->ndev->name);
1495 if (!base_res) {
1496 dev_err(&dc->ndev->dev, "hdmi: request_mem_region failed\n");
1497 err = -EBUSY;
1498 goto err_free_hdmi;
1499 }
1500
1501 base = ioremap(res->start, resource_size(res));
1502 if (!base) {
1503 dev_err(&dc->ndev->dev, "hdmi: registers can't be mapped\n");
1504 err = -EBUSY;
1505 goto err_release_resource_reg;
1506 }
1507
1508 clk = clk_get(&dc->ndev->dev, "hdmi");
1509 if (IS_ERR_OR_NULL(clk)) {
1510 dev_err(&dc->ndev->dev, "hdmi: can't get clock\n");
1511 err = -ENOENT;
1512 goto err_iounmap_reg;
1513 }
1514
1515 disp1_clk = clk_get_sys("tegradc.0", NULL);
1516 if (IS_ERR_OR_NULL(disp1_clk)) {
1517 dev_err(&dc->ndev->dev, "hdmi: can't disp1 clock\n");
1518 err = -ENOENT;
1519 goto err_put_clock;
1520 }
1521
1522 disp2_clk = clk_get_sys("tegradc.1", NULL);
1523 if (IS_ERR_OR_NULL(disp2_clk)) {
1524 dev_err(&dc->ndev->dev, "hdmi: can't disp2 clock\n");
1525 err = -ENOENT;
1526 goto err_put_clock;
1527 }
1528
1529#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1530 hdmi->hda_clk = clk_get_sys("tegra30-hda", "hda");
1531 if (IS_ERR_OR_NULL(hdmi->hda_clk)) {
1532 dev_err(&dc->ndev->dev, "hdmi: can't get hda clock\n");
1533 err = -ENOENT;
1534 goto err_put_clock;
1535 }
1536
1537 hdmi->hda2codec_clk = clk_get_sys("tegra30-hda", "hda2codec");
1538 if (IS_ERR_OR_NULL(hdmi->hda2codec_clk)) {
1539 dev_err(&dc->ndev->dev, "hdmi: can't get hda2codec clock\n");
1540 err = -ENOENT;
1541 goto err_put_clock;
1542 }
1543
1544 hdmi->hda2hdmi_clk = clk_get_sys("tegra30-hda", "hda2hdmi");
1545 if (IS_ERR_OR_NULL(hdmi->hda2hdmi_clk)) {
1546 dev_err(&dc->ndev->dev, "hdmi: can't get hda2hdmi clock\n");
1547 err = -ENOENT;
1548 goto err_put_clock;
1549 }
1550#endif
1551
1552 /* TODO: support non-hotplug */
1553 if (request_irq(gpio_to_irq(dc->out->hotplug_gpio), tegra_dc_hdmi_irq,
1554 IRQF_DISABLED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
1555 dev_name(&dc->ndev->dev), dc)) {
1556 dev_err(&dc->ndev->dev, "hdmi: request_irq %d failed\n",
1557 gpio_to_irq(dc->out->hotplug_gpio));
1558 err = -EBUSY;
1559 goto err_put_clock;
1560 }
1561
1562 hdmi->edid = tegra_edid_create(dc->out->dcc_bus);
1563 if (IS_ERR_OR_NULL(hdmi->edid)) {
1564 dev_err(&dc->ndev->dev, "hdmi: can't create edid\n");
1565 err = PTR_ERR(hdmi->edid);
1566 goto err_free_irq;
1567 }
1568
1569#ifdef CONFIG_TEGRA_NVHDCP
1570 hdmi->nvhdcp = tegra_nvhdcp_create(hdmi, dc->ndev->id,
1571 dc->out->dcc_bus);
1572 if (IS_ERR_OR_NULL(hdmi->nvhdcp)) {
1573 dev_err(&dc->ndev->dev, "hdmi: can't create nvhdcp\n");
1574 err = PTR_ERR(hdmi->nvhdcp);
1575 goto err_edid_destroy;
1576 }
1577#else
1578 hdmi->nvhdcp = NULL;
1579#endif
1580
1581 INIT_DELAYED_WORK(&hdmi->work, tegra_dc_hdmi_detect_worker);
1582
1583 hdmi->dc = dc;
1584 hdmi->base = base;
1585 hdmi->base_res = base_res;
1586 hdmi->clk = clk;
1587 hdmi->disp1_clk = disp1_clk;
1588 hdmi->disp2_clk = disp2_clk;
1589 hdmi->suspended = false;
1590 hdmi->eld_retrieved= false;
1591 hdmi->clk_enabled = false;
1592 hdmi->audio_freq = 44100;
1593 hdmi->audio_source = AUTO;
1594 spin_lock_init(&hdmi->suspend_lock);
1595
1596#ifdef CONFIG_SWITCH
1597 hdmi->hpd_switch.name = "hdmi";
1598 ret = switch_dev_register(&hdmi->hpd_switch);
1599
1600 if (!ret)
1601 ret = device_create_file(hdmi->hpd_switch.dev,
1602 &dev_attr_underscan);
1603 BUG_ON(ret != 0);
1604#endif
1605
1606 dc->out->depth = 24;
1607
1608 tegra_dc_set_outdata(dc, hdmi);
1609
1610 dc_hdmi = hdmi;
1611 /* boards can select default content protection policy */
1612 if (dc->out->flags & TEGRA_DC_OUT_NVHDCP_POLICY_ON_DEMAND)
1613 tegra_nvhdcp_set_policy(hdmi->nvhdcp,
1614 TEGRA_NVHDCP_POLICY_ON_DEMAND);
1615 else
1616 tegra_nvhdcp_set_policy(hdmi->nvhdcp,
1617 TEGRA_NVHDCP_POLICY_ALWAYS_ON);
1618
1619 tegra_dc_hdmi_debug_create(hdmi);
1620
1621 return 0;
1622
1623err_edid_destroy:
1624 tegra_edid_destroy(hdmi->edid);
1625err_free_irq:
1626 free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc);
1627err_put_clock:
1628#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1629 if (!IS_ERR_OR_NULL(hdmi->hda2hdmi_clk))
1630 clk_put(hdmi->hda2hdmi_clk);
1631 if (!IS_ERR_OR_NULL(hdmi->hda2codec_clk))
1632 clk_put(hdmi->hda2codec_clk);
1633 if (!IS_ERR_OR_NULL(hdmi->hda_clk))
1634 clk_put(hdmi->hda_clk);
1635#endif
1636 if (!IS_ERR_OR_NULL(disp2_clk))
1637 clk_put(disp2_clk);
1638 if (!IS_ERR_OR_NULL(disp1_clk))
1639 clk_put(disp1_clk);
1640 if (!IS_ERR_OR_NULL(clk))
1641 clk_put(clk);
1642err_iounmap_reg:
1643 iounmap(base);
1644err_release_resource_reg:
1645 release_resource(base_res);
1646err_free_hdmi:
1647 kfree(hdmi);
1648 return err;
1649}
1650
1651static void tegra_dc_hdmi_destroy(struct tegra_dc *dc)
1652{
1653 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1654
1655 free_irq(gpio_to_irq(dc->out->hotplug_gpio), dc);
1656 cancel_delayed_work_sync(&hdmi->work);
1657#ifdef CONFIG_SWITCH
1658 switch_dev_unregister(&hdmi->hpd_switch);
1659#endif
1660 iounmap(hdmi->base);
1661 release_resource(hdmi->base_res);
1662#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1663 clk_put(hdmi->hda2hdmi_clk);
1664 clk_put(hdmi->hda2codec_clk);
1665 clk_put(hdmi->hda_clk);
1666#endif
1667 clk_put(hdmi->clk);
1668 clk_put(hdmi->disp1_clk);
1669 clk_put(hdmi->disp2_clk);
1670 tegra_edid_destroy(hdmi->edid);
1671 tegra_nvhdcp_destroy(hdmi->nvhdcp);
1672
1673 kfree(hdmi);
1674
1675}
1676
1677static void tegra_dc_hdmi_setup_audio_fs_tables(struct tegra_dc *dc)
1678{
1679 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1680 int i;
1681 unsigned freqs[] = {
1682 32000,
1683 44100,
1684 48000,
1685 88200,
1686 96000,
1687 176400,
1688 192000,
1689 };
1690
1691 for (i = 0; i < ARRAY_SIZE(freqs); i++) {
1692 unsigned f = freqs[i];
1693 unsigned eight_half;
1694 unsigned delta;;
1695
1696 if (f > 96000)
1697 delta = 2;
1698 else if (f > 48000)
1699 delta = 6;
1700 else
1701 delta = 9;
1702
1703 eight_half = (8 * HDMI_AUDIOCLK_FREQ) / (f * 128);
1704 tegra_hdmi_writel(hdmi, AUDIO_FS_LOW(eight_half - delta) |
1705 AUDIO_FS_HIGH(eight_half + delta),
1706 HDMI_NV_PDISP_AUDIO_FS(i));
1707 }
1708}
1709
1710#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1711static void tegra_dc_hdmi_setup_eld_buff(struct tegra_dc *dc)
1712{
1713 int i;
1714 int j;
1715 u8 tmp;
1716
1717 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1718
1719 /* program ELD stuff */
1720 for (i = 0; i < HDMI_ELD_MONITOR_NAME_INDEX; i++) {
1721 switch (i) {
1722 case HDMI_ELD_VER_INDEX:
1723 tmp = (hdmi->eld.eld_ver << 3);
1724 tegra_hdmi_writel(hdmi, (i << 8) | tmp,
1725 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1726 break;
1727 case HDMI_ELD_BASELINE_LEN_INDEX:
1728 break;
1729 case HDMI_ELD_CEA_VER_MNL_INDEX:
1730 tmp = (hdmi->eld.cea_edid_ver << 5);
1731 tmp |= (hdmi->eld.mnl & 0x1f);
1732 tegra_hdmi_writel(hdmi, (i << 8) | tmp,
1733 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1734 break;
1735 case HDMI_ELD_SAD_CNT_CON_TYP_SAI_HDCP_INDEX:
1736 tmp = (hdmi->eld.sad_count << 4);
1737 tmp |= (hdmi->eld.conn_type & 0xC);
1738 tmp |= (hdmi->eld.support_ai & 0x2);
1739 tmp |= (hdmi->eld.support_hdcp & 0x1);
1740 tegra_hdmi_writel(hdmi, (i << 8) | tmp,
1741 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1742 break;
1743 case HDMI_ELD_AUD_SYNC_DELAY_INDEX:
1744 tegra_hdmi_writel(hdmi, (i << 8) | (hdmi->eld.aud_synch_delay),
1745 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1746 break;
1747 case HDMI_ELD_SPK_ALLOC_INDEX:
1748 tegra_hdmi_writel(hdmi, (i << 8) | (hdmi->eld.spk_alloc),
1749 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1750 break;
1751 case HDMI_ELD_PORT_ID_INDEX:
1752 for (j = 0; j < 8;j++) {
1753 tegra_hdmi_writel(hdmi, ((i +j) << 8) | (hdmi->eld.port_id[j]),
1754 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1755 }
1756 break;
1757 case HDMI_ELD_MANF_NAME_INDEX:
1758 for (j = 0; j < 2;j++) {
1759 tegra_hdmi_writel(hdmi, ((i +j) << 8) | (hdmi->eld.manufacture_id[j]),
1760 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1761 }
1762 break;
1763 case HDMI_ELD_PRODUCT_CODE_INDEX:
1764 for (j = 0; j < 2;j++) {
1765 tegra_hdmi_writel(hdmi, ((i +j) << 8) | (hdmi->eld.product_id[j]),
1766 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1767 }
1768 break;
1769 }
1770 }
1771 for (j = 0; j < hdmi->eld.mnl;j++) {
1772 tegra_hdmi_writel(hdmi, ((j + HDMI_ELD_MONITOR_NAME_INDEX) << 8) |
1773 (hdmi->eld.monitor_name[j]),
1774 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1775 }
1776 for (j = 0; j < hdmi->eld.sad_count;j++) {
1777 tegra_hdmi_writel(hdmi, ((j + HDMI_ELD_MONITOR_NAME_INDEX + hdmi->eld.mnl) << 8) |
1778 (hdmi->eld.sad[j]),
1779 HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0);
1780 }
1781 /* set presence andvalid bit */
1782 tegra_hdmi_writel(hdmi, 3, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0);
1783}
1784#endif
1785
1786static int tegra_dc_hdmi_setup_audio(struct tegra_dc *dc, unsigned audio_freq,
1787 unsigned audio_source)
1788{
1789 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1790 const struct tegra_hdmi_audio_config *config;
1791 unsigned long audio_n;
1792#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1793 unsigned long reg_addr = 0;
1794#endif
1795 unsigned a_source = AUDIO_CNTRL0_SOURCE_SELECT_AUTO;
1796
1797 if (HDA == audio_source)
1798 a_source = AUDIO_CNTRL0_SOURCE_SELECT_HDAL;
1799 else if (SPDIF == audio_source)
1800 a_source = AUDIO_CNTRL0_SOURCE_SELECT_SPDIF;
1801
1802#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1803 tegra_hdmi_writel(hdmi,a_source | AUDIO_CNTRL0_INJECT_NULLSMPL,
1804 HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0);
1805 tegra_hdmi_writel(hdmi,
1806 AUDIO_CNTRL0_ERROR_TOLERANCE(6) |
1807 AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0),
1808 HDMI_NV_PDISP_AUDIO_CNTRL0);
1809#else
1810 tegra_hdmi_writel(hdmi,
1811 AUDIO_CNTRL0_ERROR_TOLERANCE(6) |
1812 AUDIO_CNTRL0_FRAMES_PER_BLOCK(0xc0) |
1813 a_source,
1814 HDMI_NV_PDISP_AUDIO_CNTRL0);
1815#endif
1816 config = tegra_hdmi_get_audio_config(audio_freq, dc->mode.pclk);
1817 if (!config) {
1818 dev_err(&dc->ndev->dev,
1819 "hdmi: can't set audio to %d at %d pix_clock",
1820 audio_freq, dc->mode.pclk);
1821 return -EINVAL;
1822 }
1823
1824 tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_HDMI_ACR_CTRL);
1825
1826 audio_n = AUDIO_N_RESETF | AUDIO_N_GENERATE_ALTERNALTE |
1827 AUDIO_N_VALUE(config->n - 1);
1828 tegra_hdmi_writel(hdmi, audio_n, HDMI_NV_PDISP_AUDIO_N);
1829
1830 tegra_hdmi_writel(hdmi, ACR_SUBPACK_N(config->n) | ACR_ENABLE,
1831 HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH);
1832
1833 tegra_hdmi_writel(hdmi, ACR_SUBPACK_CTS(config->cts),
1834 HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW);
1835
1836 tegra_hdmi_writel(hdmi, SPARE_HW_CTS | SPARE_FORCE_SW_CTS |
1837 SPARE_CTS_RESET_VAL(1),
1838 HDMI_NV_PDISP_HDMI_SPARE);
1839
1840 audio_n &= ~AUDIO_N_RESETF;
1841 tegra_hdmi_writel(hdmi, audio_n, HDMI_NV_PDISP_AUDIO_N);
1842
1843#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1844 switch (audio_freq) {
1845 case AUDIO_FREQ_32K:
1846 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320_0;
1847 break;
1848 case AUDIO_FREQ_44_1K:
1849 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441_0;
1850 break;
1851 case AUDIO_FREQ_48K:
1852 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480_0;
1853 break;
1854 case AUDIO_FREQ_88_2K:
1855 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882_0;
1856 break;
1857 case AUDIO_FREQ_96K:
1858 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960_0;
1859 break;
1860 case AUDIO_FREQ_176_4K:
1861 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764_0;
1862 break;
1863 case AUDIO_FREQ_192K:
1864 reg_addr = HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920_0;
1865 break;
1866 }
1867
1868 tegra_hdmi_writel(hdmi, config->aval, reg_addr);
1869#endif
1870 tegra_dc_hdmi_setup_audio_fs_tables(dc);
1871
1872 return 0;
1873}
1874
1875int tegra_hdmi_setup_audio_freq_source(unsigned audio_freq, unsigned audio_source)
1876{
1877 struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
1878
1879 if (!hdmi)
1880 return -EAGAIN;
1881
1882 /* check for know freq */
1883 if (AUDIO_FREQ_32K == audio_freq ||
1884 AUDIO_FREQ_44_1K== audio_freq ||
1885 AUDIO_FREQ_48K== audio_freq ||
1886 AUDIO_FREQ_88_2K== audio_freq ||
1887 AUDIO_FREQ_96K== audio_freq ||
1888 AUDIO_FREQ_176_4K== audio_freq ||
1889 AUDIO_FREQ_192K== audio_freq) {
1890 /* If we can program HDMI, then proceed */
1891 if (hdmi->clk_enabled)
1892 tegra_dc_hdmi_setup_audio(hdmi->dc, audio_freq,audio_source);
1893
1894 /* Store it for using it in enable */
1895 hdmi->audio_freq = audio_freq;
1896 hdmi->audio_source = audio_source;
1897 }
1898 else
1899 return -EINVAL;
1900
1901 return 0;
1902}
1903EXPORT_SYMBOL(tegra_hdmi_setup_audio_freq_source);
1904
1905#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
1906int tegra_hdmi_setup_hda_presence()
1907{
1908 struct tegra_dc_hdmi_data *hdmi = dc_hdmi;
1909
1910 if (!hdmi)
1911 return -EAGAIN;
1912
1913 if (hdmi->clk_enabled && hdmi->eld_retrieved) {
1914 /* If HDA_PRESENCE is already set reset it */
1915 if (tegra_hdmi_readl(hdmi,
1916 HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0))
1917 tegra_hdmi_writel(hdmi, 0,
1918 HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0);
1919
1920 tegra_dc_hdmi_setup_eld_buff(hdmi->dc);
1921 }
1922 else
1923 return -ENODEV;
1924
1925 return 0;
1926}
1927EXPORT_SYMBOL(tegra_hdmi_setup_hda_presence);
1928#endif
1929
1930static void tegra_dc_hdmi_write_infopack(struct tegra_dc *dc, int header_reg,
1931 u8 type, u8 version, void *data, int len)
1932{
1933 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1934 u32 subpack[2]; /* extra byte for zero padding of subpack */
1935 int i;
1936 u8 csum;
1937
1938 /* first byte of data is the checksum */
1939 csum = type + version + len - 1;
1940 for (i = 1; i < len; i++)
1941 csum +=((u8 *)data)[i];
1942 ((u8 *)data)[0] = 0x100 - csum;
1943
1944 tegra_hdmi_writel(hdmi, INFOFRAME_HEADER_TYPE(type) |
1945 INFOFRAME_HEADER_VERSION(version) |
1946 INFOFRAME_HEADER_LEN(len - 1),
1947 header_reg);
1948
1949 /* The audio inforame only has one set of subpack registers. The hdmi
1950 * block pads the rest of the data as per the spec so we have to fixup
1951 * the length before filling in the subpacks.
1952 */
1953 if (header_reg == HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER)
1954 len = 6;
1955
1956 /* each subpack 7 bytes devided into:
1957 * subpack_low - bytes 0 - 3
1958 * subpack_high - bytes 4 - 6 (with byte 7 padded to 0x00)
1959 */
1960 for (i = 0; i < len; i++) {
1961 int subpack_idx = i % 7;
1962
1963 if (subpack_idx == 0)
1964 memset(subpack, 0x0, sizeof(subpack));
1965
1966 ((u8 *)subpack)[subpack_idx] = ((u8 *)data)[i];
1967
1968 if (subpack_idx == 6 || (i + 1 == len)) {
1969 int reg = header_reg + 1 + (i / 7) * 2;
1970
1971 tegra_hdmi_writel(hdmi, subpack[0], reg);
1972 tegra_hdmi_writel(hdmi, subpack[1], reg + 1);
1973 }
1974 }
1975}
1976
1977static void tegra_dc_hdmi_setup_avi_infoframe(struct tegra_dc *dc, bool dvi)
1978{
1979 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
1980 struct hdmi_avi_infoframe avi;
1981
1982 if (dvi) {
1983 tegra_hdmi_writel(hdmi, 0x0,
1984 HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL);
1985 return;
1986 }
1987
1988 memset(&avi, 0x0, sizeof(avi));
1989
1990 avi.r = HDMI_AVI_R_SAME;
1991
1992 if (dc->mode.v_active == 480) {
1993 if (dc->mode.h_active == 640) {
1994 avi.m = HDMI_AVI_M_4_3;
1995 avi.vic = 1;
1996 } else {
1997 avi.m = HDMI_AVI_M_16_9;
1998 avi.vic = 3;
1999 }
2000 } else if (dc->mode.v_active == 576) {
2001 /* CEC modes 17 and 18 differ only by the pysical size of the
2002 * screen so we have to calculation the physical aspect
2003 * ratio. 4 * 10 / 3 is 13
2004 */
2005 if ((dc->out->h_size * 10) / dc->out->v_size > 14) {
2006 avi.m = HDMI_AVI_M_16_9;
2007 avi.vic = 18;
2008 } else {
2009 avi.m = HDMI_AVI_M_4_3;
2010 avi.vic = 17;
2011 }
2012 } else if (dc->mode.v_active == 720 ||
2013 (dc->mode.v_active == 1470 && dc->mode.stereo_mode)) {
2014 /* VIC for both 720p and 720p 3D mode */
2015 avi.m = HDMI_AVI_M_16_9;
2016 if (dc->mode.h_front_porch == 110)
2017 avi.vic = 4; /* 60 Hz */
2018 else
2019 avi.vic = 19; /* 50 Hz */
2020 } else if (dc->mode.v_active == 1080 ||
2021 (dc->mode.v_active == 2205 && dc->mode.stereo_mode)) {
2022 /* VIC for both 1080p and 1080p 3D mode */
2023 avi.m = HDMI_AVI_M_16_9;
2024 if (dc->mode.h_front_porch == 88)
2025 avi.vic = 16; /* 60 Hz */
2026 else if (dc->mode.h_front_porch == 528)
2027 avi.vic = 31; /* 50 Hz */
2028 else
2029 avi.vic = 32; /* 24 Hz */
2030 } else {
2031 avi.m = HDMI_AVI_M_16_9;
2032 avi.vic = 0;
2033 }
2034
2035
2036 tegra_dc_hdmi_write_infopack(dc, HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER,
2037 HDMI_INFOFRAME_TYPE_AVI,
2038 HDMI_AVI_VERSION,
2039 &avi, sizeof(avi));
2040
2041 tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE,
2042 HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL);
2043}
2044
2045static void tegra_dc_hdmi_setup_stereo_infoframe(struct tegra_dc *dc)
2046{
2047 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
2048 struct hdmi_stereo_infoframe stereo;
2049 u32 val;
2050
2051 if (!dc->mode.stereo_mode) {
2052 val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
2053 val &= ~GENERIC_CTRL_ENABLE;
2054 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
2055 return;
2056 }
2057
2058 memset(&stereo, 0x0, sizeof(stereo));
2059
2060 stereo.regid0 = 0x03;
2061 stereo.regid1 = 0x0c;
2062 stereo.regid2 = 0x00;
2063 stereo.hdmi_video_format = 2; /* 3D_Structure present */
2064#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
2065 stereo._3d_structure = 0; /* frame packing */
2066#else
2067 stereo._3d_structure = 8; /* side-by-side (half) */
2068 stereo._3d_ext_data = 0; /* something which fits into 00XX bit req */
2069#endif
2070
2071 tegra_dc_hdmi_write_infopack(dc, HDMI_NV_PDISP_HDMI_GENERIC_HEADER,
2072 HDMI_INFOFRAME_TYPE_VENDOR,
2073 HDMI_VENDOR_VERSION,
2074 &stereo, 6);
2075
2076 val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
2077 val |= GENERIC_CTRL_ENABLE;
2078
2079 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
2080}
2081
2082static void tegra_dc_hdmi_setup_audio_infoframe(struct tegra_dc *dc, bool dvi)
2083{
2084 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
2085 struct hdmi_audio_infoframe audio;
2086
2087 if (dvi) {
2088 tegra_hdmi_writel(hdmi, 0x0,
2089 HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL);
2090 return;
2091 }
2092
2093 memset(&audio, 0x0, sizeof(audio));
2094
2095 audio.cc = HDMI_AUDIO_CC_2;
2096 tegra_dc_hdmi_write_infopack(dc, HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER,
2097 HDMI_INFOFRAME_TYPE_AUDIO,
2098 HDMI_AUDIO_VERSION,
2099 &audio, sizeof(audio));
2100
2101 tegra_hdmi_writel(hdmi, INFOFRAME_CTRL_ENABLE,
2102 HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL);
2103}
2104
2105static void tegra_dc_hdmi_setup_tdms(struct tegra_dc_hdmi_data *hdmi,
2106 const struct tdms_config *tc)
2107{
2108 tegra_hdmi_writel(hdmi, tc->pll0, HDMI_NV_PDISP_SOR_PLL0);
2109 tegra_hdmi_writel(hdmi, tc->pll1, HDMI_NV_PDISP_SOR_PLL1);
2110
2111 tegra_hdmi_writel(hdmi, tc->pe_current, HDMI_NV_PDISP_PE_CURRENT);
2112
2113 tegra_hdmi_writel(hdmi,
2114 tc->drive_current | DRIVE_CURRENT_FUSE_OVERRIDE,
2115 HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT);
2116}
2117
2118static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
2119{
2120 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
2121 int pulse_start;
2122 int dispclk_div_8_2;
2123 int retries;
2124 int rekey;
2125 int err;
2126 unsigned long val;
2127 unsigned i;
2128 unsigned long oldrate;
2129
2130 /* enbale power, clocks, resets, etc. */
2131
2132 /* The upstream DC needs to be clocked for accesses to HDMI to not
2133 * hard lock the system. Because we don't know if HDMI is conencted
2134 * to disp1 or disp2 we need to enable both until we set the DC mux.
2135 */
2136 clk_enable(hdmi->disp1_clk);
2137 clk_enable(hdmi->disp2_clk);
2138
2139#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
2140 /* Enabling HDA clocks before asserting HDA PD and ELDV bits */
2141 clk_enable(hdmi->hda_clk);
2142 clk_enable(hdmi->hda2codec_clk);
2143 clk_enable(hdmi->hda2hdmi_clk);
2144#endif
2145
2146 /* back off multiplier before attaching to parent at new rate. */
2147 oldrate = clk_get_rate(hdmi->clk);
2148 clk_set_rate(hdmi->clk, oldrate / 2);
2149
2150 tegra_dc_setup_clk(dc, hdmi->clk);
2151 clk_set_rate(hdmi->clk, dc->mode.pclk);
2152
2153 clk_enable(hdmi->clk);
2154 tegra_periph_reset_assert(hdmi->clk);
2155 mdelay(1);
2156 tegra_periph_reset_deassert(hdmi->clk);
2157
2158 /* TODO: copy HDCP keys from KFUSE to HDMI */
2159
2160 /* Program display timing registers: handled by dc */
2161
2162 /* program HDMI registers and SOR sequencer */
2163
2164 tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS);
2165 tegra_dc_writel(dc, DITHER_CONTROL_DISABLE | BASE_COLOR_SIZE888,
2166 DC_DISP_DISP_COLOR_CONTROL);
2167
2168 /* video_preamble uses h_pulse2 */
2169 pulse_start = dc->mode.h_ref_to_sync + dc->mode.h_sync_width +
2170 dc->mode.h_back_porch - 10;
2171 tegra_dc_writel(dc, H_PULSE_2_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0);
2172 tegra_dc_writel(dc,
2173 PULSE_MODE_NORMAL |
2174 PULSE_POLARITY_HIGH |
2175 PULSE_QUAL_VACTIVE |
2176 PULSE_LAST_END_A,
2177 DC_DISP_H_PULSE2_CONTROL);
2178 tegra_dc_writel(dc, PULSE_START(pulse_start) | PULSE_END(pulse_start + 8),
2179 DC_DISP_H_PULSE2_POSITION_A);
2180
2181 tegra_hdmi_writel(hdmi,
2182 VSYNC_WINDOW_END(0x210) |
2183 VSYNC_WINDOW_START(0x200) |
2184 VSYNC_WINDOW_ENABLE,
2185 HDMI_NV_PDISP_HDMI_VSYNC_WINDOW);
2186
2187 tegra_hdmi_writel(hdmi,
2188 (dc->ndev->id ? HDMI_SRC_DISPLAYB : HDMI_SRC_DISPLAYA) |
2189 ARM_VIDEO_RANGE_LIMITED,
2190 HDMI_NV_PDISP_INPUT_CONTROL);
2191
2192 clk_disable(hdmi->disp1_clk);
2193 clk_disable(hdmi->disp2_clk);
2194
2195 dispclk_div_8_2 = clk_get_rate(hdmi->clk) / 1000000 * 4;
2196 tegra_hdmi_writel(hdmi,
2197 SOR_REFCLK_DIV_INT(dispclk_div_8_2 >> 2) |
2198 SOR_REFCLK_DIV_FRAC(dispclk_div_8_2),
2199 HDMI_NV_PDISP_SOR_REFCLK);
2200
2201 hdmi->clk_enabled = true;
2202
2203 if (!hdmi->dvi) {
2204 err = tegra_dc_hdmi_setup_audio(dc, hdmi->audio_freq,
2205 hdmi->audio_source);
2206
2207 if (err < 0)
2208 hdmi->dvi = true;
2209 }
2210
2211#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
2212 if (hdmi->eld_retrieved)
2213 tegra_dc_hdmi_setup_eld_buff(dc);
2214#endif
2215
2216 rekey = HDMI_REKEY_DEFAULT;
2217 val = HDMI_CTRL_REKEY(rekey);
2218 val |= HDMI_CTRL_MAX_AC_PACKET((dc->mode.h_sync_width +
2219 dc->mode.h_back_porch +
2220 dc->mode.h_front_porch -
2221 rekey - 18) / 32);
2222 if (!hdmi->dvi)
2223 val |= HDMI_CTRL_ENABLE;
2224 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_HDMI_CTRL);
2225
2226 if (hdmi->dvi)
2227 tegra_hdmi_writel(hdmi, 0x0,
2228 HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
2229 else
2230 tegra_hdmi_writel(hdmi, GENERIC_CTRL_AUDIO,
2231 HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
2232
2233 tegra_dc_hdmi_setup_avi_infoframe(dc, hdmi->dvi);
2234 tegra_dc_hdmi_setup_audio_infoframe(dc, hdmi->dvi);
2235 tegra_dc_hdmi_setup_stereo_infoframe(dc);
2236
2237 /* TMDS CONFIG */
2238 for (i = 0; i < ARRAY_SIZE(tdms_config); i++) {
2239 if (dc->mode.pclk <= tdms_config[i].pclk) {
2240 tegra_dc_hdmi_setup_tdms(hdmi, &tdms_config[i]);
2241 break;
2242 }
2243 }
2244
2245 tegra_hdmi_writel(hdmi,
2246 SOR_SEQ_CTL_PU_PC(0) |
2247 SOR_SEQ_PU_PC_ALT(0) |
2248 SOR_SEQ_PD_PC(8) |
2249 SOR_SEQ_PD_PC_ALT(8),
2250 HDMI_NV_PDISP_SOR_SEQ_CTL);
2251
2252 val = SOR_SEQ_INST_WAIT_TIME(1) |
2253 SOR_SEQ_INST_WAIT_UNITS_VSYNC |
2254 SOR_SEQ_INST_HALT |
2255 SOR_SEQ_INST_PIN_A_LOW |
2256 SOR_SEQ_INST_PIN_B_LOW |
2257 SOR_SEQ_INST_DRIVE_PWM_OUT_LO;
2258
2259 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_SEQ_INST0);
2260 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_SEQ_INST8);
2261
2262 val = 0x1c800;
2263 val &= ~SOR_CSTM_ROTCLK(~0);
2264 val |= SOR_CSTM_ROTCLK(2);
2265 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_CSTM);
2266
2267
2268 tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND);
2269 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
2270 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
2271
2272
2273 /* start SOR */
2274 tegra_hdmi_writel(hdmi,
2275 SOR_PWR_NORMAL_STATE_PU |
2276 SOR_PWR_NORMAL_START_NORMAL |
2277 SOR_PWR_SAFE_STATE_PD |
2278 SOR_PWR_SETTING_NEW_TRIGGER,
2279 HDMI_NV_PDISP_SOR_PWR);
2280 tegra_hdmi_writel(hdmi,
2281 SOR_PWR_NORMAL_STATE_PU |
2282 SOR_PWR_NORMAL_START_NORMAL |
2283 SOR_PWR_SAFE_STATE_PD |
2284 SOR_PWR_SETTING_NEW_DONE,
2285 HDMI_NV_PDISP_SOR_PWR);
2286
2287 retries = 1000;
2288 do {
2289 BUG_ON(--retries < 0);
2290 val = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR);
2291 } while (val & SOR_PWR_SETTING_NEW_PENDING);
2292
2293 val = SOR_STATE_ASY_CRCMODE_COMPLETE |
2294 SOR_STATE_ASY_OWNER_HEAD0 |
2295 SOR_STATE_ASY_SUBOWNER_BOTH |
2296 SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A |
2297 SOR_STATE_ASY_DEPOL_POS;
2298
2299 if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC)
2300 val |= SOR_STATE_ASY_HSYNCPOL_NEG;
2301 else
2302 val |= SOR_STATE_ASY_HSYNCPOL_POS;
2303
2304 if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC)
2305 val |= SOR_STATE_ASY_VSYNCPOL_NEG;
2306 else
2307 val |= SOR_STATE_ASY_VSYNCPOL_POS;
2308
2309 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE2);
2310
2311 val = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL;
2312 tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE1);
2313
2314 tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0);
2315 tegra_hdmi_writel(hdmi, SOR_STATE_UPDATE, HDMI_NV_PDISP_SOR_STATE0);
2316 tegra_hdmi_writel(hdmi, val | SOR_STATE_ATTACHED,
2317 HDMI_NV_PDISP_SOR_STATE1);
2318 tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0);
2319
2320 tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS);
2321
2322 tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
2323 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
2324 DC_CMD_DISPLAY_POWER_CONTROL);
2325
2326 tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
2327 tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
2328 tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
2329
2330 tegra_nvhdcp_set_plug(hdmi->nvhdcp, 1);
2331}
2332
2333static void tegra_dc_hdmi_disable(struct tegra_dc *dc)
2334{
2335 struct tegra_dc_hdmi_data *hdmi = tegra_dc_get_outdata(dc);
2336
2337 tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
2338
2339#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
2340 tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0);
2341 /* sleep 1ms before disabling clocks to ensure HDA gets the interrupt */
2342 msleep(1);
2343 clk_disable(hdmi->hda2hdmi_clk);
2344 clk_disable(hdmi->hda2codec_clk);
2345 clk_disable(hdmi->hda_clk);
2346#endif
2347 tegra_periph_reset_assert(hdmi->clk);
2348 hdmi->clk_enabled = false;
2349 clk_disable(hdmi->clk);
2350 tegra_dvfs_set_rate(hdmi->clk, 0);
2351}
2352
2353struct tegra_dc_out_ops tegra_dc_hdmi_ops = {
2354 .init = tegra_dc_hdmi_init,
2355 .destroy = tegra_dc_hdmi_destroy,
2356 .enable = tegra_dc_hdmi_enable,
2357 .disable = tegra_dc_hdmi_disable,
2358 .detect = tegra_dc_hdmi_detect,
2359 .suspend = tegra_dc_hdmi_suspend,
2360 .resume = tegra_dc_hdmi_resume,
2361};
2362
2363struct tegra_dc_edid *tegra_dc_get_edid(struct tegra_dc *dc)
2364{
2365 struct tegra_dc_hdmi_data *hdmi;
2366
2367 /* TODO: Support EDID on non-HDMI devices */
2368 if (dc->out->type != TEGRA_DC_OUT_HDMI)
2369 return ERR_PTR(-ENODEV);
2370
2371 hdmi = tegra_dc_get_outdata(dc);
2372
2373 return tegra_edid_get_data(hdmi->edid);
2374}
2375EXPORT_SYMBOL(tegra_dc_get_edid);
2376
2377void tegra_dc_put_edid(struct tegra_dc_edid *edid)
2378{
2379 tegra_edid_put_data(edid);
2380}
2381EXPORT_SYMBOL(tegra_dc_put_edid);
diff --git a/drivers/video/tegra/dc/hdmi.h b/drivers/video/tegra/dc/hdmi.h
new file mode 100644
index 00000000000..702ab16e87f
--- /dev/null
+++ b/drivers/video/tegra/dc/hdmi.h
@@ -0,0 +1,222 @@
1/*
2 * drivers/video/tegra/dc/hdmi.h
3 *
4 * non-tegra specific HDMI declarations
5 *
6 * Copyright (C) 2010 Google, Inc.
7 * Author: Erik Gilling <konkers@android.com>
8 *
9 * Copyright (C) 2010-2011 NVIDIA Corporation
10 *
11 * This software is licensed under the terms of the GNU General Public
12 * License version 2, as published by the Free Software Foundation, and
13 * may be copied, distributed, and modified under those terms.
14 *
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
22#ifndef __DRIVERS_VIDEO_TEGRA_DC_HDMI_H
23#define __DRIVERS_VIDEO_TEGRA_DC_HDMI_H
24
25#define HDMI_INFOFRAME_TYPE_VENDOR 0x81
26#define HDMI_INFOFRAME_TYPE_AVI 0x82
27#define HDMI_INFOFRAME_TYPE_SPD 0x83
28#define HDMI_INFOFRAME_TYPE_AUDIO 0x84
29#define HDMI_INFOFRAME_TYPE_MPEG_SRC 0x85
30#define HDMI_INFOFRAME_TYPE_NTSC_VBI 0x86
31
32/* all fields little endian */
33struct hdmi_avi_infoframe {
34 /* PB0 */
35 u8 csum;
36
37 /* PB1 */
38 unsigned s:2; /* scan information */
39 unsigned b:2; /* bar info data valid */
40 unsigned a:1; /* active info present */
41 unsigned y:2; /* RGB or YCbCr */
42 unsigned res1:1;
43
44 /* PB2 */
45 unsigned r:4; /* active format aspect ratio */
46 unsigned m:2; /* picture aspect ratio */
47 unsigned c:2; /* colorimetry */
48
49 /* PB3 */
50 unsigned sc:2; /* scan information */
51 unsigned q:2; /* quantization range */
52 unsigned ec:3; /* extended colorimetry */
53 unsigned itc:1; /* it content */
54
55 /* PB4 */
56 unsigned vic:7; /* video format id code */
57 unsigned res4:1;
58
59 /* PB5 */
60 unsigned pr:4; /* pixel repetition factor */
61 unsigned cn:2; /* it content type*/
62 unsigned yq:2; /* ycc quantization range */
63
64 /* PB6-7 */
65 u16 top_bar_end_line;
66
67 /* PB8-9 */
68 u16 bot_bar_start_line;
69
70 /* PB10-11 */
71 u16 left_bar_end_pixel;
72
73 /* PB12-13 */
74 u16 right_bar_start_pixel;
75} __attribute__((packed));
76
77#define HDMI_AVI_VERSION 0x02
78
79#define HDMI_AVI_Y_RGB 0x0
80#define HDMI_AVI_Y_YCBCR_422 0x1
81#define HDMI_AVI_Y_YCBCR_444 0x2
82
83#define HDMI_AVI_B_VERT 0x1
84#define HDMI_AVI_B_HORIZ 0x2
85
86#define HDMI_AVI_S_NONE 0x0
87#define HDMI_AVI_S_OVERSCAN 0x1
88#define HDMI_AVI_S_UNDERSCAN 0x2
89
90#define HDMI_AVI_C_NONE 0x0
91#define HDMI_AVI_C_SMPTE 0x1
92#define HDMI_AVI_C_ITU_R 0x2
93#define HDMI_AVI_C_EXTENDED 0x4
94
95#define HDMI_AVI_M_4_3 0x1
96#define HDMI_AVI_M_16_9 0x2
97
98#define HDMI_AVI_R_SAME 0x8
99#define HDMI_AVI_R_4_3_CENTER 0x9
100#define HDMI_AVI_R_16_9_CENTER 0xa
101#define HDMI_AVI_R_14_9_CENTER 0xb
102
103/* all fields little endian */
104struct hdmi_audio_infoframe {
105 /* PB0 */
106 u8 csum;
107
108 /* PB1 */
109 unsigned cc:3; /* channel count */
110 unsigned res1:1;
111 unsigned ct:4; /* coding type */
112
113 /* PB2 */
114 unsigned ss:2; /* sample size */
115 unsigned sf:3; /* sample frequency */
116 unsigned res2:3;
117
118 /* PB3 */
119 unsigned cxt:5; /* coding extention type */
120 unsigned res3:3;
121
122 /* PB4 */
123 u8 ca; /* channel/speaker allocation */
124
125 /* PB5 */
126 unsigned res5:3;
127 unsigned lsv:4; /* level shift value */
128 unsigned dm_inh:1; /* downmix inhibit */
129
130 /* PB6-10 reserved */
131 u8 res6;
132 u8 res7;
133 u8 res8;
134 u8 res9;
135 u8 res10;
136} __attribute__((packed));
137
138#define HDMI_AUDIO_VERSION 0x01
139
140#define HDMI_AUDIO_CC_STREAM 0x0 /* specified by audio stream */
141#define HDMI_AUDIO_CC_2 0x1
142#define HDMI_AUDIO_CC_3 0x2
143#define HDMI_AUDIO_CC_4 0x3
144#define HDMI_AUDIO_CC_5 0x4
145#define HDMI_AUDIO_CC_6 0x5
146#define HDMI_AUDIO_CC_7 0x6
147#define HDMI_AUDIO_CC_8 0x7
148
149#define HDMI_AUDIO_CT_STREAM 0x0 /* specified by audio stream */
150#define HDMI_AUDIO_CT_PCM 0x1
151#define HDMI_AUDIO_CT_AC3 0x2
152#define HDMI_AUDIO_CT_MPEG1 0x3
153#define HDMI_AUDIO_CT_MP3 0x4
154#define HDMI_AUDIO_CT_MPEG2 0x5
155#define HDMI_AUDIO_CT_AAC_LC 0x6
156#define HDMI_AUDIO_CT_DTS 0x7
157#define HDMI_AUDIO_CT_ATRAC 0x8
158#define HDMI_AUDIO_CT_DSD 0x9
159#define HDMI_AUDIO_CT_E_AC3 0xa
160#define HDMI_AUDIO_CT_DTS_HD 0xb
161#define HDMI_AUDIO_CT_MLP 0xc
162#define HDMI_AUDIO_CT_DST 0xd
163#define HDMI_AUDIO_CT_WMA_PRO 0xe
164#define HDMI_AUDIO_CT_CXT 0xf
165
166#define HDMI_AUDIO_SF_STREAM 0x0 /* specified by audio stream */
167#define HDMI_AUIDO_SF_32K 0x1
168#define HDMI_AUDIO_SF_44_1K 0x2
169#define HDMI_AUDIO_SF_48K 0x3
170#define HDMI_AUDIO_SF_88_2K 0x4
171#define HDMI_AUDIO_SF_96K 0x5
172#define HDMI_AUDIO_SF_176_4K 0x6
173#define HDMI_AUDIO_SF_192K 0x7
174
175#define HDMI_AUDIO_SS_STREAM 0x0 /* specified by audio stream */
176#define HDMI_AUDIO_SS_16BIT 0x1
177#define HDMI_AUDIO_SS_20BIT 0x2
178#define HDMI_AUDIO_SS_24BIT 0x3
179
180#define HDMI_AUDIO_CXT_CT 0x0 /* refer to coding in CT */
181#define HDMI_AUDIO_CXT_HE_AAC 0x1
182#define HDMI_AUDIO_CXT_HE_AAC_V2 0x2
183#define HDMI_AUDIO_CXT_MPEG_SURROUND 0x3
184
185/* all fields little endian */
186struct hdmi_stereo_infoframe {
187 /* PB0 */
188 u8 csum;
189
190 /* PB1 */
191 u8 regid0;
192
193 /* PB2 */
194 u8 regid1;
195
196 /* PB3 */
197 u8 regid2;
198
199 /* PB4 */
200 unsigned res1:5;
201 unsigned hdmi_video_format:3;
202
203 /* PB5 */
204 unsigned res2:4;
205 unsigned _3d_structure:4;
206
207 /* PB6*/
208 unsigned res3:4;
209 unsigned _3d_ext_data:4;
210
211} __attribute__((packed));
212
213#define HDMI_VENDOR_VERSION 0x01
214
215struct tegra_dc_hdmi_data;
216
217unsigned long tegra_hdmi_readl(struct tegra_dc_hdmi_data *hdmi,
218 unsigned long reg);
219void tegra_hdmi_writel(struct tegra_dc_hdmi_data *hdmi,
220 unsigned long val, unsigned long reg);
221
222#endif
diff --git a/drivers/video/tegra/dc/hdmi_reg.h b/drivers/video/tegra/dc/hdmi_reg.h
new file mode 100644
index 00000000000..0bdda43199e
--- /dev/null
+++ b/drivers/video/tegra/dc/hdmi_reg.h
@@ -0,0 +1,478 @@
1/*
2 * drivers/video/tegra/dc/hdmi_reg.h
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#ifndef __DRIVERS_VIDEO_TEGRA_DC_HDMI_REG_H
19#define __DRIVERS_VIDEO_TEGRA_DC_HDMI_REG_H
20
21#define HDMI_CTXSW 0x00
22#define HDMI_NV_PDISP_SOR_STATE0 0x01
23#define SOR_STATE_UPDATE (1 << 0)
24
25#define HDMI_NV_PDISP_SOR_STATE1 0x02
26#define SOR_STATE_ASY_HEAD_OPMODE_SLEEP (0 << 0)
27#define SOR_STATE_ASY_HEAD_OPMODE_SNOOSE (1 << 0)
28#define SOR_STATE_ASY_HEAD_OPMODE_AWAKE (2 << 0)
29#define SOR_STATE_ASY_ORMODE_SAFE (0 << 2)
30#define SOR_STATE_ASY_ORMODE_NORMAL (1 << 2)
31#define SOR_STATE_ATTACHED (1 << 3)
32#define SOR_STATE_ARM_SHOW_VGA (1 << 4)
33
34#define HDMI_NV_PDISP_SOR_STATE2 0x03
35#define SOR_STATE_ASY_OWNER_NONE (0 << 0)
36#define SOR_STATE_ASY_OWNER_HEAD0 (1 << 0)
37#define SOR_STATE_ASY_SUBOWNER_NONE (0 << 4)
38#define SOR_STATE_ASY_SUBOWNER_SUBHEAD0 (1 << 4)
39#define SOR_STATE_ASY_SUBOWNER_SUBHEAD1 (2 << 4)
40#define SOR_STATE_ASY_SUBOWNER_BOTH (3 << 4)
41#define SOR_STATE_ASY_CRCMODE_ACTIVE (0 << 6)
42#define SOR_STATE_ASY_CRCMODE_COMPLETE (1 << 6)
43#define SOR_STATE_ASY_CRCMODE_NON_ACTIVE (2 << 6)
44#define SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A (1 << 8)
45#define SOR_STATE_ASY_PROTOCOL_CUSTOM (15 << 8)
46#define SOR_STATE_ASY_HSYNCPOL_POS (0 << 12)
47#define SOR_STATE_ASY_HSYNCPOL_NEG (1 << 12)
48#define SOR_STATE_ASY_VSYNCPOL_POS (0 << 13)
49#define SOR_STATE_ASY_VSYNCPOL_NEG (1 << 13)
50#define SOR_STATE_ASY_DEPOL_POS (0 << 14)
51#define SOR_STATE_ASY_DEPOL_NEG (1 << 14)
52
53#define HDMI_NV_PDISP_RG_HDCP_AN_MSB 0x04
54#define HDMI_NV_PDISP_RG_HDCP_AN_LSB 0x05
55#define HDMI_NV_PDISP_RG_HDCP_CN_MSB 0x06
56#define HDMI_NV_PDISP_RG_HDCP_CN_LSB 0x07
57#define HDMI_NV_PDISP_RG_HDCP_AKSV_MSB 0x08
58#define HDMI_NV_PDISP_RG_HDCP_AKSV_LSB 0x09
59#define HDMI_NV_PDISP_RG_HDCP_BKSV_MSB 0x0a
60#define REPEATER (1 << 31)
61#define HDMI_NV_PDISP_RG_HDCP_BKSV_LSB 0x0b
62#define HDMI_NV_PDISP_RG_HDCP_CKSV_MSB 0x0c
63#define HDMI_NV_PDISP_RG_HDCP_CKSV_LSB 0x0d
64#define HDMI_NV_PDISP_RG_HDCP_DKSV_MSB 0x0e
65#define HDMI_NV_PDISP_RG_HDCP_DKSV_LSB 0x0f
66#define HDMI_NV_PDISP_RG_HDCP_CTRL 0x10
67#define HDCP_RUN_YES (1 << 0)
68#define CRYPT_ENABLED (1 << 1)
69#define ONEONE_ENABLED (1 << 3)
70#define AN_VALID (1 << 8)
71#define R0_VALID (1 << 9)
72#define SPRIME_VALID (1 << 10)
73#define MPRIME_VALID (1 << 11)
74#define SROM_ERR (1 << 13)
75#define HDMI_NV_PDISP_RG_HDCP_CMODE 0x11
76#define TMDS0_LINK0 (1 << 4)
77#define READ_S (1 << 0)
78#define READ_M (2 << 0)
79#define HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB 0x12
80#define HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB 0x13
81#define HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB 0x14
82#define STATUS_CS (1 << 6)
83#define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2 0x15
84#define HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1 0x16
85#define HDMI_NV_PDISP_RG_HDCP_RI 0x17
86#define HDMI_NV_PDISP_RG_HDCP_CS_MSB 0x18
87#define HDMI_NV_PDISP_RG_HDCP_CS_LSB 0x19
88#define HDMI_NV_PDISP_HDMI_AUDIO_EMU0 0x1a
89#define HDMI_NV_PDISP_HDMI_AUDIO_EMU_RDATA0 0x1b
90#define HDMI_NV_PDISP_HDMI_AUDIO_EMU1 0x1c
91#define HDMI_NV_PDISP_HDMI_AUDIO_EMU2 0x1d
92#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_CTRL 0x1e
93#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_STATUS 0x1f
94#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_HEADER 0x20
95#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_LOW 0x21
96#define HDMI_NV_PDISP_HDMI_AUDIO_INFOFRAME_SUBPACK0_HIGH 0x22
97#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_CTRL 0x23
98#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_STATUS 0x24
99#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_HEADER 0x25
100#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_LOW 0x26
101#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK0_HIGH 0x27
102#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_LOW 0x28
103#define HDMI_NV_PDISP_HDMI_AVI_INFOFRAME_SUBPACK1_HIGH 0x29
104#define INFOFRAME_CTRL_ENABLE (1 << 0)
105#define INFOFRAME_CTRL_OTHER (1 << 4)
106#define INFOFRAME_CTRL_SINGLE (1 << 8)
107
108#define INFOFRAME_HEADER_TYPE(x) ((x) & 0xff)
109#define INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
110#define INFOFRAME_HEADER_LEN(x) (((x) & 0xf) << 16)
111
112#define HDMI_NV_PDISP_HDMI_GENERIC_CTRL 0x2a
113#define GENERIC_CTRL_ENABLE (1 << 0)
114#define GENERIC_CTRL_OTHER (1 << 4)
115#define GENERIC_CTRL_SINGLE (1 << 8)
116#define GENERIC_CTRL_HBLANK (1 << 12)
117#define GENERIC_CTRL_AUDIO (1 << 16)
118
119#define HDMI_NV_PDISP_HDMI_GENERIC_STATUS 0x2b
120#define HDMI_NV_PDISP_HDMI_GENERIC_HEADER 0x2c
121#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_LOW 0x2d
122#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK0_HIGH 0x2e
123#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_LOW 0x2f
124#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK1_HIGH 0x30
125#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_LOW 0x31
126#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK2_HIGH 0x32
127#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_LOW 0x33
128#define HDMI_NV_PDISP_HDMI_GENERIC_SUBPACK3_HIGH 0x34
129#define HDMI_NV_PDISP_HDMI_ACR_CTRL 0x35
130#define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_LOW 0x36
131#define HDMI_NV_PDISP_HDMI_ACR_0320_SUBPACK_HIGH 0x37
132#define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_LOW 0x38
133#define HDMI_NV_PDISP_HDMI_ACR_0441_SUBPACK_HIGH 0x39
134#define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_LOW 0x3a
135#define HDMI_NV_PDISP_HDMI_ACR_0882_SUBPACK_HIGH 0x3b
136#define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_LOW 0x3c
137#define HDMI_NV_PDISP_HDMI_ACR_1764_SUBPACK_HIGH 0x3d
138#define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_LOW 0x3e
139#define HDMI_NV_PDISP_HDMI_ACR_0480_SUBPACK_HIGH 0x3f
140#define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_LOW 0x40
141#define HDMI_NV_PDISP_HDMI_ACR_0960_SUBPACK_HIGH 0x41
142#define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_LOW 0x42
143#define HDMI_NV_PDISP_HDMI_ACR_1920_SUBPACK_HIGH 0x43
144#define ACR_SB3(x) (((x) & 0xff) << 8)
145#define ACR_SB2(x) (((x) & 0xff) << 16)
146#define ACR_SB1(x) (((x) & 0xff) << 24)
147#define ACR_SUBPACK_CTS(x) (((x) & 0xffffff) << 8)
148
149#define ACR_SB6(x) (((x) & 0xff) << 0)
150#define ACR_SB5(x) (((x) & 0xff) << 8)
151#define ACR_SB4(x) (((x) & 0xff) << 16)
152#define ACR_ENABLE (1 << 31)
153#define ACR_SUBPACK_N(x) ((x) & 0xffffff)
154
155#define HDMI_NV_PDISP_HDMI_CTRL 0x44
156#define HDMI_CTRL_REKEY(x) (((x) & 0x7f) << 0)
157#define HDMI_CTRL_AUDIO_LAYOUT (1 << 8)
158#define HDMI_CTRL_SAMPLE_FLAT (1 << 12)
159#define HDMI_CTRL_MAX_AC_PACKET(x) (((x) & 0x1f) << 16)
160#define HDMI_CTRL_ENABLE (1 << 30)
161
162#define HDMI_NV_PDISP_HDMI_VSYNC_KEEPOUT 0x45
163#define HDMI_NV_PDISP_HDMI_VSYNC_WINDOW 0x46
164#define VSYNC_WINDOW_END(x) (((x) & 0x3ff) << 0)
165#define VSYNC_WINDOW_START(x) (((x) & 0x3ff) << 16)
166#define VSYNC_WINDOW_ENABLE (1 << 31)
167
168#define HDMI_NV_PDISP_HDMI_GCP_CTRL 0x47
169#define HDMI_NV_PDISP_HDMI_GCP_STATUS 0x48
170#define HDMI_NV_PDISP_HDMI_GCP_SUBPACK 0x49
171#define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS1 0x4a
172#define HDMI_NV_PDISP_HDMI_CHANNEL_STATUS2 0x4b
173#define HDMI_NV_PDISP_HDMI_EMU0 0x4c
174#define HDMI_NV_PDISP_HDMI_EMU1 0x4d
175#define HDMI_NV_PDISP_HDMI_EMU1_RDATA 0x4e
176#define HDMI_NV_PDISP_HDMI_SPARE 0x4f
177#define SPARE_HW_CTS (1 << 0)
178#define SPARE_FORCE_SW_CTS (1 << 1)
179#define SPARE_CTS_RESET_VAL(x) (((x) & 0x7) << 16)
180#define SPARE_ACR_PRIORITY_HIGH (0 << 31)
181#define SPARE_ACR_PRIORITY_LOW (1 << 31)
182
183#define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS1 0x50
184#define HDMI_NV_PDISP_HDMI_SPDIF_CHN_STATUS2 0x51
185#define HDMI_NV_PDISP_HDCPRIF_ROM_CTRL 0x53
186#define HDMI_NV_PDISP_SOR_CAP 0x54
187#define HDMI_NV_PDISP_SOR_PWR 0x55
188#define SOR_PWR_NORMAL_STATE_PD (0 << 0)
189#define SOR_PWR_NORMAL_STATE_PU (1 << 0)
190#define SOR_PWR_NORMAL_START_NORMAL (0 << 1)
191#define SOR_PWR_NORMAL_START_ALT (1 << 1)
192#define SOR_PWR_SAFE_STATE_PD (0 << 16)
193#define SOR_PWR_SAFE_STATE_PU (1 << 16)
194#define SOR_PWR_SAFE_START_NORMAL (0 << 17)
195#define SOR_PWR_SAFE_START_ALT (1 << 17)
196#define SOR_PWR_HALT_DELAY (1 << 24)
197#define SOR_PWR_MODE (1 << 28)
198#define SOR_PWR_SETTING_NEW_DONE (0 << 31)
199#define SOR_PWR_SETTING_NEW_PENDING (1 << 31)
200#define SOR_PWR_SETTING_NEW_TRIGGER (1 << 31)
201
202#define HDMI_NV_PDISP_SOR_TEST 0x56
203#define HDMI_NV_PDISP_SOR_PLL0 0x57
204#define SOR_PLL_PWR (1 << 0)
205#define SOR_PLL_PDBG (1 << 1)
206#define SOR_PLL_VCOPD (1 << 2)
207#define SOR_PLL_PDPORT (1 << 3)
208#define SOR_PLL_RESISTORSEL (1 << 4)
209#define SOR_PLL_PULLDOWN (1 << 5)
210#define SOR_PLL_VCOCAP(x) (((x) & 0xf) << 8)
211#define SOR_PLL_BG_V17_S(x) (((x) & 0xf) << 12)
212#define SOR_PLL_FILTER(x) (((x) & 0xf) << 16)
213#define SOR_PLL_ICHPMP(x) (((x) & 0xf) << 24)
214#define SOR_PLL_TX_REG_LOAD(x) (((x) & 0x3) << 28)
215
216#define HDMI_NV_PDISP_SOR_PLL1 0x58
217#define SOR_PLL_TMDS_TERM_ENABLE (1 << 8)
218#define SOR_PLL_TMDS_TERMADJ(x) (((x) & 0xf) << 9)
219#define SOR_PLL_LOADADJ(x) (((x) & 0xf) << 20)
220#define SOR_PLL_PE_EN (1 << 28)
221#define SOR_PLL_HALF_FULL_PE (1 << 29)
222#define SOR_PLL_S_D_PIN_PE (1 << 30)
223
224#define HDMI_NV_PDISP_SOR_PLL2 0x59
225#define HDMI_NV_PDISP_SOR_CSTM 0x5a
226#define SOR_CSTM_PD_TXDA_0 (1 << 0)
227#define SOR_CSTM_PD_TXDA_1 (1 << 1)
228#define SOR_CSTM_PD_TXDA_2 (1 << 2)
229#define SOR_CSTM_PD_TXDA_3 (1 << 3)
230#define SOR_CSTM_PD_TXDB_0 (1 << 4)
231#define SOR_CSTM_PD_TXDB_1 (1 << 5)
232#define SOR_CSTM_PD_TXDB_2 (1 << 6)
233#define SOR_CSTM_PD_TXDB_3 (1 << 7)
234#define SOR_CSTM_PD_TXCA (1 << 8)
235#define SOR_CSTM_PD_TXCB (1 << 9)
236#define SOR_CSTM_UPPER (1 << 11)
237#define SOR_CSTM_MODE(x) (((x) & 0x3) << 12)
238#define SOR_CSTM_LINKACTA (1 << 14)
239#define SOR_CSTM_LINKACTB (1 << 15)
240#define SOR_CSTM_LVDS_EN (1 << 16)
241#define SOR_CSTM_DUP_SYNC (1 << 17)
242#define SOR_CSTM_NEW_MODE (1 << 18)
243#define SOR_CSTM_BALANCED (1 << 19)
244#define SOR_CSTM_PLLDIV (1 << 21)
245#define SOR_CSTM_ROTCLK(x) (((x) & 0xf) << 24)
246#define SOR_CSTM_ROTDAT(x) (((x) & 0x7) << 28)
247
248#define HDMI_NV_PDISP_SOR_LVDS 0x5b
249#define HDMI_NV_PDISP_SOR_CRCA 0x5c
250#define HDMI_NV_PDISP_SOR_CRCB 0x5d
251#define HDMI_NV_PDISP_SOR_BLANK 0x5e
252#define HDMI_NV_PDISP_SOR_SEQ_CTL 0x5f
253#define SOR_SEQ_CTL_PU_PC(x) (((x) & 0xf) << 0)
254#define SOR_SEQ_PU_PC_ALT(x) (((x) & 0xf) << 4)
255#define SOR_SEQ_PD_PC(x) (((x) & 0xf) << 8)
256#define SOR_SEQ_PD_PC_ALT(x) (((x) & 0xf) << 12)
257#define SOR_SEQ_PC(x) (((x) & 0xf) << 16)
258#define SOR_SEQ_STATUS (1 << 28)
259#define SOR_SEQ_SWITCH (1 << 30)
260
261#define HDMI_NV_PDISP_SOR_SEQ_INST0 0x60
262#define HDMI_NV_PDISP_SOR_SEQ_INST1 0x61
263#define HDMI_NV_PDISP_SOR_SEQ_INST2 0x62
264#define HDMI_NV_PDISP_SOR_SEQ_INST3 0x63
265#define HDMI_NV_PDISP_SOR_SEQ_INST4 0x64
266#define HDMI_NV_PDISP_SOR_SEQ_INST5 0x65
267#define HDMI_NV_PDISP_SOR_SEQ_INST6 0x66
268#define HDMI_NV_PDISP_SOR_SEQ_INST7 0x67
269#define HDMI_NV_PDISP_SOR_SEQ_INST8 0x68
270#define HDMI_NV_PDISP_SOR_SEQ_INST9 0x69
271#define HDMI_NV_PDISP_SOR_SEQ_INSTA 0x6a
272#define HDMI_NV_PDISP_SOR_SEQ_INSTB 0x6b
273#define HDMI_NV_PDISP_SOR_SEQ_INSTC 0x6c
274#define HDMI_NV_PDISP_SOR_SEQ_INSTD 0x6d
275#define HDMI_NV_PDISP_SOR_SEQ_INSTE 0x6e
276#define HDMI_NV_PDISP_SOR_SEQ_INSTF 0x6f
277#define SOR_SEQ_INST_WAIT_TIME(x) (((x) & 0x3ff) << 0)
278#define SOR_SEQ_INST_WAIT_UNITS_US (0 << 12)
279#define SOR_SEQ_INST_WAIT_UNITS_MS (1 << 12)
280#define SOR_SEQ_INST_WAIT_UNITS_VSYNC (2 << 12)
281#define SOR_SEQ_INST_HALT (1 << 15)
282#define SOR_SEQ_INST_PIN_A_LOW (0 << 21)
283#define SOR_SEQ_INST_PIN_A_HIGH (1 << 21)
284#define SOR_SEQ_INST_PIN_B_LOW (0 << 22)
285#define SOR_SEQ_INST_PIN_B_HIGH (1 << 22)
286#define SOR_SEQ_INST_DRIVE_PWM_OUT_LO (1 << 23)
287#define SOR_SEQ_INST_TRISTATE_IOS (1 << 24)
288#define SOR_SEQ_INST_SOR_SEQ_INST_BLACK_DATA (1 << 25)
289#define SOR_SEQ_INST_BLANK_DE (1 << 26)
290#define SOR_SEQ_INST_BLANK_H (1 << 27)
291#define SOR_SEQ_INST_BLANK_V (1 << 28)
292#define SOR_SEQ_INST_ASSERT_PLL_RESETV (1 << 29)
293#define SOR_SEQ_INST_POWERDOWN_MACRO (1 << 30)
294#define SOR_SEQ_INST_PLL_PULLDOWN (1 << 31)
295
296#define HDMI_NV_PDISP_SOR_VCRCA0 0x72
297#define HDMI_NV_PDISP_SOR_VCRCA1 0x73
298#define HDMI_NV_PDISP_SOR_CCRCA0 0x74
299#define HDMI_NV_PDISP_SOR_CCRCA1 0x75
300#define HDMI_NV_PDISP_SOR_EDATAA0 0x76
301#define HDMI_NV_PDISP_SOR_EDATAA1 0x77
302#define HDMI_NV_PDISP_SOR_COUNTA0 0x78
303#define HDMI_NV_PDISP_SOR_COUNTA1 0x79
304#define HDMI_NV_PDISP_SOR_DEBUGA0 0x7a
305#define HDMI_NV_PDISP_SOR_DEBUGA1 0x7b
306#define HDMI_NV_PDISP_SOR_TRIG 0x7c
307#define HDMI_NV_PDISP_SOR_MSCHECK 0x7d
308#define HDMI_NV_PDISP_SOR_LANE_DRIVE_CURRENT 0x7e
309#define DRIVE_CURRENT_LANE0(x) (((x) & 0x3f) << 0)
310#define DRIVE_CURRENT_LANE1(x) (((x) & 0x3f) << 8)
311#define DRIVE_CURRENT_LANE2(x) (((x) & 0x3f) << 16)
312#define DRIVE_CURRENT_LANE3(x) (((x) & 0x3f) << 24)
313#define DRIVE_CURRENT_FUSE_OVERRIDE (1 << 31)
314#define DRIVE_CURRENT_1_500_mA 0x00
315#define DRIVE_CURRENT_1_875_mA 0x01
316#define DRIVE_CURRENT_2_250_mA 0x02
317#define DRIVE_CURRENT_2_625_mA 0x03
318#define DRIVE_CURRENT_3_000_mA 0x04
319#define DRIVE_CURRENT_3_375_mA 0x05
320#define DRIVE_CURRENT_3_750_mA 0x06
321#define DRIVE_CURRENT_4_125_mA 0x07
322#define DRIVE_CURRENT_4_500_mA 0x08
323#define DRIVE_CURRENT_4_875_mA 0x09
324#define DRIVE_CURRENT_5_250_mA 0x0a
325#define DRIVE_CURRENT_5_625_mA 0x0b
326#define DRIVE_CURRENT_6_000_mA 0x0c
327#define DRIVE_CURRENT_6_375_mA 0x0d
328#define DRIVE_CURRENT_6_750_mA 0x0e
329#define DRIVE_CURRENT_7_125_mA 0x0f
330#define DRIVE_CURRENT_7_500_mA 0x10
331#define DRIVE_CURRENT_7_875_mA 0x11
332#define DRIVE_CURRENT_8_250_mA 0x12
333#define DRIVE_CURRENT_8_625_mA 0x13
334#define DRIVE_CURRENT_9_000_mA 0x14
335#define DRIVE_CURRENT_9_375_mA 0x15
336#define DRIVE_CURRENT_9_750_mA 0x16
337#define DRIVE_CURRENT_10_125_mA 0x17
338#define DRIVE_CURRENT_10_500_mA 0x18
339#define DRIVE_CURRENT_10_875_mA 0x19
340#define DRIVE_CURRENT_11_250_mA 0x1a
341#define DRIVE_CURRENT_11_625_mA 0x1b
342#define DRIVE_CURRENT_12_000_mA 0x1c
343#define DRIVE_CURRENT_12_375_mA 0x1d
344#define DRIVE_CURRENT_12_750_mA 0x1e
345#define DRIVE_CURRENT_13_125_mA 0x1f
346#define DRIVE_CURRENT_13_500_mA 0x20
347#define DRIVE_CURRENT_13_875_mA 0x21
348#define DRIVE_CURRENT_14_250_mA 0x22
349#define DRIVE_CURRENT_14_625_mA 0x23
350#define DRIVE_CURRENT_15_000_mA 0x24
351#define DRIVE_CURRENT_15_375_mA 0x25
352#define DRIVE_CURRENT_15_750_mA 0x26
353#define DRIVE_CURRENT_16_125_mA 0x27
354#define DRIVE_CURRENT_16_500_mA 0x28
355#define DRIVE_CURRENT_16_875_mA 0x29
356#define DRIVE_CURRENT_17_250_mA 0x2a
357#define DRIVE_CURRENT_17_625_mA 0x2b
358#define DRIVE_CURRENT_18_000_mA 0x2c
359#define DRIVE_CURRENT_18_375_mA 0x2d
360#define DRIVE_CURRENT_18_750_mA 0x2e
361#define DRIVE_CURRENT_19_125_mA 0x2f
362#define DRIVE_CURRENT_19_500_mA 0x30
363#define DRIVE_CURRENT_19_875_mA 0x31
364#define DRIVE_CURRENT_20_250_mA 0x32
365#define DRIVE_CURRENT_20_625_mA 0x33
366#define DRIVE_CURRENT_21_000_mA 0x34
367#define DRIVE_CURRENT_21_375_mA 0x35
368#define DRIVE_CURRENT_21_750_mA 0x36
369#define DRIVE_CURRENT_22_125_mA 0x37
370#define DRIVE_CURRENT_22_500_mA 0x38
371#define DRIVE_CURRENT_22_875_mA 0x39
372#define DRIVE_CURRENT_23_250_mA 0x3a
373#define DRIVE_CURRENT_23_625_mA 0x3b
374#define DRIVE_CURRENT_24_000_mA 0x3c
375#define DRIVE_CURRENT_24_375_mA 0x3d
376#define DRIVE_CURRENT_24_750_mA 0x3e
377
378#define HDMI_NV_PDISP_AUDIO_DEBUG0 0x7f
379#define HDMI_NV_PDISP_AUDIO_DEBUG1 0x80
380#define HDMI_NV_PDISP_AUDIO_DEBUG2 0x81
381/* note: datasheet defines FS1..FS7. we have FS(0)..FS(6) */
382#define HDMI_NV_PDISP_AUDIO_FS(x) (0x82 + (x))
383#define AUDIO_FS_LOW(x) (((x) & 0xfff) << 0)
384#define AUDIO_FS_HIGH(x) (((x) & 0xfff) << 16)
385
386
387#define HDMI_NV_PDISP_AUDIO_PULSE_WIDTH 0x89
388#define HDMI_NV_PDISP_AUDIO_THRESHOLD 0x8a
389#define HDMI_NV_PDISP_AUDIO_CNTRL0 0x8b
390#if !defined(CONFIG_ARCH_TEGRA_2x_SOC)
391#define HDMI_NV_PDISP_SOR_AUDIO_CNTRL0_0 0xac
392#define HDMI_NV_PDISP_SOR_AUDIO_HDA_ELD_BUFWR_0 0xbc
393#define HDMI_NV_PDISP_SOR_AUDIO_HDA_PRESENSE_0 0xbd
394#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0320_0 0xbf
395#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0441_0 0xc0
396#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0882_0 0xc1
397#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1764_0 0xc2
398#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0480_0 0xc3
399#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_0960_0 0xc4
400#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_1920_0 0xc5
401#define HDMI_NV_PDISP_SOR_AUDIO_AVAL_DEFAULT_0 0xc6
402#endif
403#define AUDIO_CNTRL0_ERROR_TOLERANCE(x) (((x) & 0xff) << 0)
404#define AUDIO_CNTRL0_SOFT_RESET (1 << 8)
405#define AUDIO_CNTRL0_SOFT_RESET_ALL (1 << 12)
406#define AUDIO_CNTRL0_SAMPLING_FREQ_UNKNOWN (1 << 16)
407#define AUDIO_CNTRL0_SAMPLING_FREQ_32K (2 << 16)
408#define AUDIO_CNTRL0_SAMPLING_FREQ_44_1K (0 << 16)
409#define AUDIO_CNTRL0_SAMPLING_FREQ_48K (2 << 16)
410#define AUDIO_CNTRL0_SAMPLING_FREQ_88_2K (8 << 16)
411#define AUDIO_CNTRL0_SAMPLING_FREQ_96K (10 << 16)
412#define AUDIO_CNTRL0_SAMPLING_FREQ_176_4K (12 << 16)
413#define AUDIO_CNTRL0_SAMPLING_FREQ_192K (14 << 16)
414#define AUDIO_CNTRL0_SOURCE_SELECT_AUTO (0 << 20)
415#define AUDIO_CNTRL0_SOURCE_SELECT_SPDIF (1 << 20)
416#define AUDIO_CNTRL0_SOURCE_SELECT_HDAL (2 << 20)
417#define AUDIO_CNTRL0_INJECT_NULLSMPL (1 << 29)
418#define AUDIO_CNTRL0_FRAMES_PER_BLOCK(x) (((x) & 0xff) << 24)
419
420#define HDMI_NV_PDISP_AUDIO_N 0x8c
421#define AUDIO_N_VALUE(x) (((x) & 0xfffff) << 0)
422#define AUDIO_N_RESETF (1 << 20)
423#define AUDIO_N_GENERATE_NORMAL (0 << 24)
424#define AUDIO_N_GENERATE_ALTERNALTE (1 << 24)
425#define AUDIO_N_LOOKUP_ENABLE (1 << 28)
426
427#define HDMI_NV_PDISP_HDCPRIF_ROM_TIMING 0x94
428#define HDMI_NV_PDISP_SOR_REFCLK 0x95
429#define SOR_REFCLK_DIV_INT(x) (((x) & 0xff) << 8)
430#define SOR_REFCLK_DIV_FRAC(x) (((x) & 0x3) << 6)
431
432#define HDMI_NV_PDISP_CRC_CONTROL 0x96
433#define HDMI_NV_PDISP_INPUT_CONTROL 0x97
434#define HDMI_SRC_DISPLAYA (0 << 0)
435#define HDMI_SRC_DISPLAYB (1 << 0)
436#define ARM_VIDEO_RANGE_FULL (0 << 1)
437#define ARM_VIDEO_RANGE_LIMITED (1 << 1)
438
439#define HDMI_NV_PDISP_SCRATCH 0x98
440#define HDMI_NV_PDISP_PE_CURRENT 0x99
441#define PE_CURRENT0(x) (((x) & 0xf) << 0)
442#define PE_CURRENT1(x) (((x) & 0xf) << 8)
443#define PE_CURRENT2(x) (((x) & 0xf) << 16)
444#define PE_CURRENT3(x) (((x) & 0xf) << 24)
445#define PE_CURRENT_0_0_mA 0x0
446#define PE_CURRENT_0_5_mA 0x1
447#define PE_CURRENT_1_0_mA 0x2
448#define PE_CURRENT_1_5_mA 0x3
449#define PE_CURRENT_2_0_mA 0x4
450#define PE_CURRENT_2_5_mA 0x5
451#define PE_CURRENT_3_0_mA 0x6
452#define PE_CURRENT_3_5_mA 0x7
453#define PE_CURRENT_4_0_mA 0x8
454#define PE_CURRENT_4_5_mA 0x9
455#define PE_CURRENT_5_0_mA 0xa
456#define PE_CURRENT_5_5_mA 0xb
457#define PE_CURRENT_6_0_mA 0xc
458#define PE_CURRENT_6_5_mA 0xd
459#define PE_CURRENT_7_0_mA 0xe
460#define PE_CURRENT_7_5_mA 0xf
461
462#define HDMI_NV_PDISP_KEY_CTRL 0x9a
463#define LOCAL_KEYS (1 << 0)
464#define AUTOINC (1 << 1)
465#define WRITE16 (1 << 4)
466#define PKEY_REQUEST_RELOAD_TRIGGER (1 << 5)
467#define PKEY_LOADED (1 << 6)
468#define HDMI_NV_PDISP_KEY_DEBUG0 0x9b
469#define HDMI_NV_PDISP_KEY_DEBUG1 0x9c
470#define HDMI_NV_PDISP_KEY_DEBUG2 0x9d
471#define HDMI_NV_PDISP_KEY_HDCP_KEY_0 0x9e
472#define HDMI_NV_PDISP_KEY_HDCP_KEY_1 0x9f
473#define HDMI_NV_PDISP_KEY_HDCP_KEY_2 0xa0
474#define HDMI_NV_PDISP_KEY_HDCP_KEY_3 0xa1
475#define HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG 0xa2
476#define HDMI_NV_PDISP_KEY_SKEY_INDEX 0xa3
477
478#endif
diff --git a/drivers/video/tegra/dc/nvhdcp.c b/drivers/video/tegra/dc/nvhdcp.c
new file mode 100644
index 00000000000..263de07a3da
--- /dev/null
+++ b/drivers/video/tegra/dc/nvhdcp.c
@@ -0,0 +1,1259 @@
1/*
2 * drivers/video/tegra/dc/nvhdcp.c
3 *
4 * Copyright (c) 2010-2011, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/kernel.h>
18#include <linux/delay.h>
19#include <linux/i2c.h>
20#include <linux/miscdevice.h>
21#include <linux/poll.h>
22#include <linux/sched.h>
23#include <linux/uaccess.h>
24#include <linux/wait.h>
25#include <linux/workqueue.h>
26#include <asm/atomic.h>
27
28#include <mach/dc.h>
29#include <mach/kfuse.h>
30
31#include <video/nvhdcp.h>
32
33#include "dc_reg.h"
34#include "dc_priv.h"
35#include "hdmi_reg.h"
36#include "hdmi.h"
37
38DECLARE_WAIT_QUEUE_HEAD(wq_worker);
39
40/* for 0x40 Bcaps */
41#define BCAPS_REPEATER (1 << 6)
42#define BCAPS_READY (1 << 5)
43#define BCAPS_11 (1 << 1) /* used for both Bcaps and Ainfo */
44
45/* for 0x41 Bstatus */
46#define BSTATUS_MAX_DEVS_EXCEEDED (1 << 7)
47#define BSTATUS_MAX_CASCADE_EXCEEDED (1 << 11)
48
49#ifdef VERBOSE_DEBUG
50#define nvhdcp_vdbg(...) \
51 printk("nvhdcp: " __VA_ARGS__)
52#else
53#define nvhdcp_vdbg(...) \
54({ \
55 if(0) \
56 printk("nvhdcp: " __VA_ARGS__); \
57 0; \
58})
59#endif
60#define nvhdcp_debug(...) \
61 pr_debug("nvhdcp: " __VA_ARGS__)
62#define nvhdcp_err(...) \
63 pr_err("nvhdcp: Error: " __VA_ARGS__)
64#define nvhdcp_info(...) \
65 pr_info("nvhdcp: " __VA_ARGS__)
66
67
68/* for nvhdcp.state */
69enum tegra_nvhdcp_state {
70 STATE_OFF,
71 STATE_UNAUTHENTICATED,
72 STATE_LINK_VERIFY,
73 STATE_RENEGOTIATE,
74};
75
76struct tegra_nvhdcp {
77 struct delayed_work work;
78 struct tegra_dc_hdmi_data *hdmi;
79 struct workqueue_struct *downstream_wq;
80 struct mutex lock;
81 struct miscdevice miscdev;
82 char name[12];
83 unsigned id;
84 bool plugged; /* true if hotplug detected */
85 atomic_t policy; /* set policy */
86 enum tegra_nvhdcp_state state; /* STATE_xxx */
87 struct i2c_client *client;
88 struct i2c_board_info info;
89 int bus;
90 u32 b_status;
91 u64 a_n;
92 u64 c_n;
93 u64 a_ksv;
94 u64 b_ksv;
95 u64 c_ksv;
96 u64 d_ksv;
97 u8 v_prime[20];
98 u64 m_prime;
99 u32 num_bksv_list;
100 u64 bksv_list[TEGRA_NVHDCP_MAX_DEVS];
101 int fail_count;
102};
103
104static inline bool nvhdcp_is_plugged(struct tegra_nvhdcp *nvhdcp)
105{
106 rmb();
107 return nvhdcp->plugged;
108}
109
110static inline bool nvhdcp_set_plugged(struct tegra_nvhdcp *nvhdcp, bool plugged)
111{
112 nvhdcp->plugged = plugged;
113 wmb();
114 return plugged;
115}
116
117static int nvhdcp_i2c_read(struct tegra_nvhdcp *nvhdcp, u8 reg,
118 size_t len, void *data)
119{
120 int status;
121 int retries = 15;
122 struct i2c_msg msg[] = {
123 {
124 .addr = 0x74 >> 1, /* primary link */
125 .flags = 0,
126 .len = 1,
127 .buf = &reg,
128 },
129 {
130 .addr = 0x74 >> 1, /* primary link */
131 .flags = I2C_M_RD,
132 .len = len,
133 .buf = data,
134 },
135 };
136
137 do {
138 if (!nvhdcp_is_plugged(nvhdcp)) {
139 nvhdcp_err("disconnect during i2c xfer\n");
140 return -EIO;
141 }
142 status = i2c_transfer(nvhdcp->client->adapter,
143 msg, ARRAY_SIZE(msg));
144 if ((status < 0) && (retries > 1))
145 msleep(250);
146 } while ((status < 0) && retries--);
147
148 if (status < 0) {
149 nvhdcp_err("i2c xfer error %d\n", status);
150 return status;
151 }
152
153 return 0;
154}
155
156static int nvhdcp_i2c_write(struct tegra_nvhdcp *nvhdcp, u8 reg,
157 size_t len, const void *data)
158{
159 int status;
160 u8 buf[len + 1];
161 struct i2c_msg msg[] = {
162 {
163 .addr = 0x74 >> 1, /* primary link */
164 .flags = 0,
165 .len = len + 1,
166 .buf = buf,
167 },
168 };
169 int retries = 15;
170
171 buf[0] = reg;
172 memcpy(buf + 1, data, len);
173
174 do {
175 if (!nvhdcp_is_plugged(nvhdcp)) {
176 nvhdcp_err("disconnect during i2c xfer\n");
177 return -EIO;
178 }
179 status = i2c_transfer(nvhdcp->client->adapter,
180 msg, ARRAY_SIZE(msg));
181 if ((status < 0) && (retries > 1))
182 msleep(250);
183 } while ((status < 0) && retries--);
184
185 if (status < 0) {
186 nvhdcp_err("i2c xfer error %d\n", status);
187 return status;
188 }
189
190 return 0;
191}
192
193static inline int nvhdcp_i2c_read8(struct tegra_nvhdcp *nvhdcp, u8 reg, u8 *val)
194{
195 return nvhdcp_i2c_read(nvhdcp, reg, 1, val);
196}
197
198static inline int nvhdcp_i2c_write8(struct tegra_nvhdcp *nvhdcp, u8 reg, u8 val)
199{
200 return nvhdcp_i2c_write(nvhdcp, reg, 1, &val);
201}
202
203static inline int nvhdcp_i2c_read16(struct tegra_nvhdcp *nvhdcp,
204 u8 reg, u16 *val)
205{
206 u8 buf[2];
207 int e;
208
209 e = nvhdcp_i2c_read(nvhdcp, reg, sizeof buf, buf);
210 if (e)
211 return e;
212
213 if (val)
214 *val = buf[0] | (u16)buf[1] << 8;
215
216 return 0;
217}
218
219static int nvhdcp_i2c_read40(struct tegra_nvhdcp *nvhdcp, u8 reg, u64 *val)
220{
221 u8 buf[5];
222 int e, i;
223 u64 n;
224
225 e = nvhdcp_i2c_read(nvhdcp, reg, sizeof buf, buf);
226 if (e)
227 return e;
228
229 for(i = 0, n = 0; i < 5; i++ ) {
230 n <<= 8;
231 n |= buf[4 - i];
232 }
233
234 if (val)
235 *val = n;
236
237 return 0;
238}
239
240static int nvhdcp_i2c_write40(struct tegra_nvhdcp *nvhdcp, u8 reg, u64 val)
241{
242 char buf[5];
243 int i;
244 for(i = 0; i < 5; i++ ) {
245 buf[i] = val;
246 val >>= 8;
247 }
248 return nvhdcp_i2c_write(nvhdcp, reg, sizeof buf, buf);
249}
250
251static int nvhdcp_i2c_write64(struct tegra_nvhdcp *nvhdcp, u8 reg, u64 val)
252{
253 char buf[8];
254 int i;
255 for(i = 0; i < 8; i++ ) {
256 buf[i] = val;
257 val >>= 8;
258 }
259 return nvhdcp_i2c_write(nvhdcp, reg, sizeof buf, buf);
260}
261
262
263/* 64-bit link encryption session random number */
264static inline u64 get_an(struct tegra_dc_hdmi_data *hdmi)
265{
266 u64 r;
267 r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AN_MSB) << 32;
268 r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AN_LSB);
269 return r;
270}
271
272/* 64-bit upstream exchange random number */
273static inline void set_cn(struct tegra_dc_hdmi_data *hdmi, u64 c_n)
274{
275 tegra_hdmi_writel(hdmi, (u32)c_n, HDMI_NV_PDISP_RG_HDCP_CN_LSB);
276 tegra_hdmi_writel(hdmi, c_n >> 32, HDMI_NV_PDISP_RG_HDCP_CN_MSB);
277}
278
279
280/* 40-bit transmitter's key selection vector */
281static inline u64 get_aksv(struct tegra_dc_hdmi_data *hdmi)
282{
283 u64 r;
284 r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AKSV_MSB) << 32;
285 r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_AKSV_LSB);
286 return r;
287}
288
289/* 40-bit receiver's key selection vector */
290static inline void set_bksv(struct tegra_dc_hdmi_data *hdmi, u64 b_ksv, bool repeater)
291{
292 if (repeater)
293 b_ksv |= (u64)REPEATER << 32;
294 tegra_hdmi_writel(hdmi, (u32)b_ksv, HDMI_NV_PDISP_RG_HDCP_BKSV_LSB);
295 tegra_hdmi_writel(hdmi, b_ksv >> 32, HDMI_NV_PDISP_RG_HDCP_BKSV_MSB);
296}
297
298
299/* 40-bit software's key selection vector */
300static inline void set_cksv(struct tegra_dc_hdmi_data *hdmi, u64 c_ksv)
301{
302 tegra_hdmi_writel(hdmi, (u32)c_ksv, HDMI_NV_PDISP_RG_HDCP_CKSV_LSB);
303 tegra_hdmi_writel(hdmi, c_ksv >> 32, HDMI_NV_PDISP_RG_HDCP_CKSV_MSB);
304}
305
306/* 40-bit connection state */
307static inline u64 get_cs(struct tegra_dc_hdmi_data *hdmi)
308{
309 u64 r;
310 r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CS_MSB) << 32;
311 r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CS_LSB);
312 return r;
313}
314
315/* 40-bit upstream key selection vector */
316static inline u64 get_dksv(struct tegra_dc_hdmi_data *hdmi)
317{
318 u64 r;
319 r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_DKSV_MSB) << 32;
320 r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_DKSV_LSB);
321 return r;
322}
323
324/* 64-bit encrypted M0 value */
325static inline u64 get_mprime(struct tegra_dc_hdmi_data *hdmi)
326{
327 u64 r;
328 r = (u64)tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_MPRIME_MSB) << 32;
329 r |= tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_MPRIME_LSB);
330 return r;
331}
332
333static inline u16 get_transmitter_ri(struct tegra_dc_hdmi_data *hdmi)
334{
335 return tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_RI);
336}
337
338static inline int get_receiver_ri(struct tegra_nvhdcp *nvhdcp, u16 *r)
339{
340 return nvhdcp_i2c_read16(nvhdcp, 0x8, r); /* long read */
341}
342
343static int get_bcaps(struct tegra_nvhdcp *nvhdcp, u8 *b_caps)
344{
345 return nvhdcp_i2c_read8(nvhdcp, 0x40, b_caps);
346}
347
348static int get_ksvfifo(struct tegra_nvhdcp *nvhdcp,
349 unsigned num_bksv_list, u64 *ksv_list)
350{
351 u8 *buf, *p;
352 int e;
353 unsigned i;
354 size_t buf_len = num_bksv_list * 5;
355
356 if (!ksv_list || num_bksv_list > TEGRA_NVHDCP_MAX_DEVS)
357 return -EINVAL;
358
359 if (num_bksv_list == 0)
360 return 0;
361
362 buf = kmalloc(buf_len, GFP_KERNEL);
363 if (IS_ERR_OR_NULL(buf))
364 return -ENOMEM;
365
366 e = nvhdcp_i2c_read(nvhdcp, 0x43, buf_len, buf);
367 if (e) {
368 kfree(buf);
369 return e;
370 }
371
372 /* load 40-bit keys from repeater into array of u64 */
373 p = buf;
374 for (i = 0; i < num_bksv_list; i++) {
375 ksv_list[i] = p[0] | ((u64)p[1] << 8) | ((u64)p[2] << 16)
376 | ((u64)p[3] << 24) | ((u64)p[4] << 32);
377 p += 5;
378 }
379
380 kfree(buf);
381 return 0;
382}
383
384/* get V' 160-bit SHA-1 hash from repeater */
385static int get_vprime(struct tegra_nvhdcp *nvhdcp, u8 *v_prime)
386{
387 int e, i;
388
389 for (i = 0; i < 20; i += 4) {
390 e = nvhdcp_i2c_read(nvhdcp, 0x20 + i, 4, v_prime + i);
391 if (e)
392 return e;
393 }
394 return 0;
395}
396
397
398/* set or clear RUN_YES */
399static void hdcp_ctrl_run(struct tegra_dc_hdmi_data *hdmi, bool v)
400{
401 u32 ctrl;
402
403 if (v) {
404 ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CTRL);
405 ctrl |= HDCP_RUN_YES;
406 } else {
407 ctrl = 0;
408 }
409
410 tegra_hdmi_writel(hdmi, ctrl, HDMI_NV_PDISP_RG_HDCP_CTRL);
411}
412
413/* wait for any bits in mask to be set in HDMI_NV_PDISP_RG_HDCP_CTRL
414 * sleeps up to 120mS */
415static int wait_hdcp_ctrl(struct tegra_dc_hdmi_data *hdmi, u32 mask, u32 *v)
416{
417 int retries = 13;
418 u32 ctrl;
419
420 do {
421 ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CTRL);
422 if ((ctrl & mask)) {
423 if (v)
424 *v = ctrl;
425 break;
426 }
427 if (retries > 1)
428 msleep(10);
429 } while (--retries);
430 if (!retries) {
431 nvhdcp_err("ctrl read timeout (mask=0x%x)\n", mask);
432 return -EIO;
433 }
434 return 0;
435}
436
437/* wait for bits in mask to be set to value in HDMI_NV_PDISP_KEY_CTRL
438 * waits up to 100mS */
439static int wait_key_ctrl(struct tegra_dc_hdmi_data *hdmi, u32 mask, u32 value)
440{
441 int retries = 101;
442 u32 ctrl;
443
444 do {
445 msleep(1);
446 ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_KEY_CTRL);
447 if (((ctrl ^ value) & mask) == 0)
448 break;
449 } while (--retries);
450 if (!retries) {
451 nvhdcp_err("key ctrl read timeout (mask=0x%x)\n", mask);
452 return -EIO;
453 }
454 return 0;
455}
456
457/* check that key selection vector is well formed.
458 * NOTE: this function assumes KSV has already been checked against
459 * revocation list.
460 */
461static int verify_ksv(u64 k)
462{
463 unsigned i;
464
465 /* count set bits, must be exactly 20 set to be valid */
466 for(i = 0; k; i++)
467 k ^= k & -k;
468
469 return (i != 20) ? -EINVAL : 0;
470}
471
472/* get Status and Kprime signature - READ_S on TMDS0_LINK0 only */
473static int get_s_prime(struct tegra_nvhdcp *nvhdcp, struct tegra_nvhdcp_packet *pkt)
474{
475 struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi;
476 u32 sp_msb, sp_lsb1, sp_lsb2;
477 int e;
478
479 /* if connection isn't authenticated ... */
480 mutex_lock(&nvhdcp->lock);
481 if (nvhdcp->state != STATE_LINK_VERIFY) {
482 memset(pkt, 0, sizeof *pkt);
483 pkt->packet_results = TEGRA_NVHDCP_RESULT_LINK_FAILED;
484 e = 0;
485 goto err;
486 }
487
488 pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL;
489
490 /* we will be taking c_n, c_ksv as input */
491 if (!(pkt->value_flags & TEGRA_NVHDCP_FLAG_CN)
492 || !(pkt->value_flags & TEGRA_NVHDCP_FLAG_CKSV)) {
493 nvhdcp_err("missing value_flags (0x%x)\n", pkt->value_flags);
494 e = -EINVAL;
495 goto err;
496 }
497
498 pkt->value_flags = 0;
499
500 pkt->a_ksv = nvhdcp->a_ksv;
501 pkt->a_n = nvhdcp->a_n;
502 pkt->value_flags = TEGRA_NVHDCP_FLAG_AKSV | TEGRA_NVHDCP_FLAG_AN;
503
504 nvhdcp_vdbg("%s():cn %llx cksv %llx\n", __func__, pkt->c_n, pkt->c_ksv);
505
506 set_cn(hdmi, pkt->c_n);
507
508 tegra_hdmi_writel(hdmi, TMDS0_LINK0 | READ_S,
509 HDMI_NV_PDISP_RG_HDCP_CMODE);
510
511 set_cksv(hdmi, pkt->c_ksv);
512
513 e = wait_hdcp_ctrl(hdmi, SPRIME_VALID, NULL);
514 if (e) {
515 nvhdcp_err("Sprime read timeout\n");
516 pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL;
517 e = -EIO;
518 goto err;
519 }
520
521 msleep(50);
522
523 /* read 56-bit Sprime plus 16 status bits */
524 sp_msb = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_SPRIME_MSB);
525 sp_lsb1 = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB1);
526 sp_lsb2 = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_SPRIME_LSB2);
527
528 /* top 8 bits of LSB2 and bottom 8 bits of MSB hold status bits. */
529 pkt->hdcp_status = ( sp_msb << 8 ) | ( sp_lsb2 >> 24);
530 pkt->value_flags |= TEGRA_NVHDCP_FLAG_S;
531
532 /* 56-bit Kprime */
533 pkt->k_prime = ((u64)(sp_lsb2 & 0xffffff) << 32) | sp_lsb1;
534 pkt->value_flags |= TEGRA_NVHDCP_FLAG_KP;
535
536 /* is connection state supported? */
537 if (sp_msb & STATUS_CS) {
538 pkt->cs = get_cs(hdmi);
539 pkt->value_flags |= TEGRA_NVHDCP_FLAG_CS;
540 }
541
542 /* load Dksv */
543 pkt->d_ksv = get_dksv(hdmi);
544 if (verify_ksv(pkt->d_ksv)) {
545 nvhdcp_err("Dksv invalid!\n");
546 pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL;
547 e = -EIO; /* treat bad Dksv as I/O error */
548 }
549 pkt->value_flags |= TEGRA_NVHDCP_FLAG_DKSV;
550
551 /* copy current Bksv */
552 pkt->b_ksv = nvhdcp->b_ksv;
553 pkt->value_flags |= TEGRA_NVHDCP_FLAG_BKSV;
554
555 pkt->packet_results = TEGRA_NVHDCP_RESULT_SUCCESS;
556 mutex_unlock(&nvhdcp->lock);
557 return 0;
558
559err:
560 mutex_unlock(&nvhdcp->lock);
561 return e;
562}
563
564/* get M prime - READ_M on TMDS0_LINK0 only */
565static inline int get_m_prime(struct tegra_nvhdcp *nvhdcp, struct tegra_nvhdcp_packet *pkt)
566{
567 struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi;
568 int e;
569
570 pkt->packet_results = TEGRA_NVHDCP_RESULT_UNSUCCESSFUL;
571
572 /* if connection isn't authenticated ... */
573 mutex_lock(&nvhdcp->lock);
574 if (nvhdcp->state != STATE_LINK_VERIFY) {
575 memset(pkt, 0, sizeof *pkt);
576 pkt->packet_results = TEGRA_NVHDCP_RESULT_LINK_FAILED;
577 e = 0;
578 goto err;
579 }
580
581 pkt->a_ksv = nvhdcp->a_ksv;
582 pkt->a_n = nvhdcp->a_n;
583 pkt->value_flags = TEGRA_NVHDCP_FLAG_AKSV | TEGRA_NVHDCP_FLAG_AN;
584
585 set_cn(hdmi, pkt->c_n);
586
587 tegra_hdmi_writel(hdmi, TMDS0_LINK0 | READ_M,
588 HDMI_NV_PDISP_RG_HDCP_CMODE);
589
590 /* Cksv write triggers Mprime update */
591 set_cksv(hdmi, pkt->c_ksv);
592
593 e = wait_hdcp_ctrl(hdmi, MPRIME_VALID, NULL);
594 if (e) {
595 nvhdcp_err("Mprime read timeout\n");
596 e = -EIO;
597 goto err;
598 }
599 msleep(50);
600
601 /* load Mprime */
602 pkt->m_prime = get_mprime(hdmi);
603 pkt->value_flags |= TEGRA_NVHDCP_FLAG_MP;
604
605 pkt->b_status = nvhdcp->b_status;
606 pkt->value_flags |= TEGRA_NVHDCP_FLAG_BSTATUS;
607
608 /* copy most recent KSVFIFO, if it is non-zero */
609 pkt->num_bksv_list = nvhdcp->num_bksv_list;
610 if( nvhdcp->num_bksv_list ) {
611 BUILD_BUG_ON(sizeof(pkt->bksv_list) != sizeof(nvhdcp->bksv_list));
612 memcpy(pkt->bksv_list, nvhdcp->bksv_list,
613 nvhdcp->num_bksv_list * sizeof(*pkt->bksv_list));
614 pkt->value_flags |= TEGRA_NVHDCP_FLAG_BKSVLIST;
615 }
616
617 /* copy v_prime */
618 BUILD_BUG_ON(sizeof(pkt->v_prime) != sizeof(nvhdcp->v_prime));
619 memcpy(pkt->v_prime, nvhdcp->v_prime, sizeof(nvhdcp->v_prime));
620 pkt->value_flags |= TEGRA_NVHDCP_FLAG_V;
621
622 /* load Dksv */
623 pkt->d_ksv = get_dksv(hdmi);
624 if (verify_ksv(pkt->d_ksv)) {
625 nvhdcp_err("Dksv invalid!\n");
626 e = -EIO;
627 goto err;
628 }
629 pkt->value_flags |= TEGRA_NVHDCP_FLAG_DKSV;
630
631 /* copy current Bksv */
632 pkt->b_ksv = nvhdcp->b_ksv;
633 pkt->value_flags |= TEGRA_NVHDCP_FLAG_BKSV;
634
635 pkt->packet_results = TEGRA_NVHDCP_RESULT_SUCCESS;
636 mutex_unlock(&nvhdcp->lock);
637 return 0;
638
639err:
640 mutex_unlock(&nvhdcp->lock);
641 return e;
642}
643
644static int load_kfuse(struct tegra_dc_hdmi_data *hdmi)
645{
646 unsigned buf[KFUSE_DATA_SZ / 4];
647 int e, i;
648 u32 ctrl;
649 u32 tmp;
650 int retries;
651
652 /* copy load kfuse into buffer - only needed for early Tegra parts */
653 e = tegra_kfuse_read(buf, sizeof buf);
654 if (e) {
655 nvhdcp_err("Kfuse read failure\n");
656 return e;
657 }
658
659 /* write the kfuse to HDMI SRAM */
660
661 tegra_hdmi_writel(hdmi, 1, HDMI_NV_PDISP_KEY_CTRL); /* LOAD_KEYS */
662
663 /* issue a reload */
664 ctrl = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_KEY_CTRL);
665 tegra_hdmi_writel(hdmi, ctrl | PKEY_REQUEST_RELOAD_TRIGGER
666 | LOCAL_KEYS , HDMI_NV_PDISP_KEY_CTRL);
667
668 e = wait_key_ctrl(hdmi, PKEY_LOADED, PKEY_LOADED);
669 if (e) {
670 nvhdcp_err("key reload timeout\n");
671 return -EIO;
672 }
673
674 tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_KEY_SKEY_INDEX);
675
676 /* wait for SRAM to be cleared */
677 retries = 6;
678 do {
679 tmp = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_KEY_DEBUG0);
680 if ((tmp & 1) == 0) break;
681 if (retries > 1)
682 mdelay(1);
683 } while (--retries);
684 if (!retries) {
685 nvhdcp_err("key SRAM clear timeout\n");
686 return -EIO;
687 }
688
689 for (i = 0; i < KFUSE_DATA_SZ / 4; i += 4) {
690
691 /* load 128-bits*/
692 tegra_hdmi_writel(hdmi, buf[i], HDMI_NV_PDISP_KEY_HDCP_KEY_0);
693 tegra_hdmi_writel(hdmi, buf[i+1], HDMI_NV_PDISP_KEY_HDCP_KEY_1);
694 tegra_hdmi_writel(hdmi, buf[i+2], HDMI_NV_PDISP_KEY_HDCP_KEY_2);
695 tegra_hdmi_writel(hdmi, buf[i+3], HDMI_NV_PDISP_KEY_HDCP_KEY_3);
696
697 /* trigger LOAD_HDCP_KEY */
698 tegra_hdmi_writel(hdmi, 0x100, HDMI_NV_PDISP_KEY_HDCP_KEY_TRIG);
699
700 tmp = LOCAL_KEYS | WRITE16;
701 if (i)
702 tmp |= AUTOINC;
703 tegra_hdmi_writel(hdmi, tmp, HDMI_NV_PDISP_KEY_CTRL);
704
705 /* wait for WRITE16 to complete */
706 e = wait_key_ctrl(hdmi, 0x10, 0); /* WRITE16 */
707 if (e) {
708 nvhdcp_err("key write timeout\n");
709 return -EIO;
710 }
711 }
712
713 return 0;
714}
715
716static int verify_link(struct tegra_nvhdcp *nvhdcp, bool wait_ri)
717{
718 struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi;
719 int retries = 3;
720 u16 old, rx, tx;
721 int e;
722
723 old = 0;
724 rx = 0;
725 tx = 0;
726 /* retry 3 times to deal with I2C link issues */
727 do {
728 if (wait_ri)
729 old = get_transmitter_ri(hdmi);
730
731 e = get_receiver_ri(nvhdcp, &rx);
732 if (!e) {
733 if (!rx) {
734 nvhdcp_err("Ri is 0!\n");
735 return -EINVAL;
736 }
737
738 tx = get_transmitter_ri(hdmi);
739 } else {
740 rx = ~tx;
741 msleep(50);
742 }
743
744 } while (wait_ri && --retries && old != tx);
745
746 nvhdcp_debug("R0 Ri poll:rx=0x%04x tx=0x%04x\n", rx, tx);
747
748 if (!nvhdcp_is_plugged(nvhdcp)) {
749 nvhdcp_err("aborting verify links - lost hdmi connection\n");
750 return -EIO;
751 }
752
753 if (rx != tx)
754 return -EINVAL;
755
756 return 0;
757}
758
759static int get_repeater_info(struct tegra_nvhdcp *nvhdcp)
760{
761 int e, retries;
762 u8 b_caps;
763 u16 b_status;
764
765 nvhdcp_vdbg("repeater found:fetching repeater info\n");
766
767 /* wait up to 5 seconds for READY on repeater */
768 retries = 51;
769 do {
770 if (!nvhdcp_is_plugged(nvhdcp)) {
771 nvhdcp_err("disconnect while waiting for repeater\n");
772 return -EIO;
773 }
774
775 e = get_bcaps(nvhdcp, &b_caps);
776 if (!e && (b_caps & BCAPS_READY)) {
777 nvhdcp_debug("Bcaps READY from repeater\n");
778 break;
779 }
780 if (retries > 1)
781 msleep(100);
782 } while (--retries);
783 if (!retries) {
784 nvhdcp_err("repeater Bcaps read timeout\n");
785 return -ETIMEDOUT;
786 }
787
788 memset(nvhdcp->v_prime, 0, sizeof nvhdcp->v_prime);
789 e = get_vprime(nvhdcp, nvhdcp->v_prime);
790 if (e) {
791 nvhdcp_err("repeater Vprime read failure!\n");
792 return e;
793 }
794
795 e = nvhdcp_i2c_read16(nvhdcp, 0x41, &b_status);
796 if (e) {
797 nvhdcp_err("Bstatus read failure!\n");
798 return e;
799 }
800
801 if (b_status & BSTATUS_MAX_DEVS_EXCEEDED) {
802 nvhdcp_err("repeater:max devices (0x%04x)\n", b_status);
803 return -EINVAL;
804 }
805
806 if (b_status & BSTATUS_MAX_CASCADE_EXCEEDED) {
807 nvhdcp_err("repeater:max cascade (0x%04x)\n", b_status);
808 return -EINVAL;
809 }
810
811 nvhdcp->b_status = b_status;
812 nvhdcp->num_bksv_list = b_status & 0x7f;
813 nvhdcp_vdbg("Bstatus 0x%x (devices: %d)\n",
814 b_status, nvhdcp->num_bksv_list);
815
816 memset(nvhdcp->bksv_list, 0, sizeof nvhdcp->bksv_list);
817 e = get_ksvfifo(nvhdcp, nvhdcp->num_bksv_list, nvhdcp->bksv_list);
818 if (e) {
819 nvhdcp_err("repeater:could not read KSVFIFO (err %d)\n", e);
820 return e;
821 }
822
823 return 0;
824}
825
826static void nvhdcp_downstream_worker(struct work_struct *work)
827{
828 struct tegra_nvhdcp *nvhdcp =
829 container_of(to_delayed_work(work), struct tegra_nvhdcp, work);
830 struct tegra_dc_hdmi_data *hdmi = nvhdcp->hdmi;
831 int e;
832 u8 b_caps;
833 u32 tmp;
834 u32 res;
835
836 nvhdcp_vdbg("%s():started thread %s\n", __func__, nvhdcp->name);
837
838 mutex_lock(&nvhdcp->lock);
839 if (nvhdcp->state == STATE_OFF) {
840 nvhdcp_err("nvhdcp failure - giving up\n");
841 goto err;
842 }
843 nvhdcp->state = STATE_UNAUTHENTICATED;
844
845 /* check plug state to terminate early in case flush_workqueue() */
846 if (!nvhdcp_is_plugged(nvhdcp)) {
847 nvhdcp_err("worker started while unplugged!\n");
848 goto lost_hdmi;
849 }
850 nvhdcp_vdbg("%s():hpd=%d\n", __func__, nvhdcp->plugged);
851
852 nvhdcp->a_ksv = 0;
853 nvhdcp->b_ksv = 0;
854 nvhdcp->a_n = 0;
855
856 e = get_bcaps(nvhdcp, &b_caps);
857 if (e) {
858 nvhdcp_err("Bcaps read failure\n");
859 goto failure;
860 }
861
862 nvhdcp_vdbg("read Bcaps = 0x%02x\n", b_caps);
863
864 nvhdcp_vdbg("kfuse loading ...\n");
865
866 /* repeater flag in Bskv must be configured before loading fuses */
867 set_bksv(hdmi, 0, (b_caps & BCAPS_REPEATER));
868
869 e = load_kfuse(hdmi);
870 if (e) {
871 nvhdcp_err("kfuse could not be loaded\n");
872 goto failure;
873 }
874
875 hdcp_ctrl_run(hdmi, 1);
876
877 nvhdcp_vdbg("wait AN_VALID ...\n");
878
879 /* wait for hardware to generate HDCP values */
880 e = wait_hdcp_ctrl(hdmi, AN_VALID | SROM_ERR, &res);
881 if (e) {
882 nvhdcp_err("An key generation timeout\n");
883 goto failure;
884 }
885 if (res & SROM_ERR) {
886 nvhdcp_err("SROM error\n");
887 goto failure;
888 }
889
890 msleep(25);
891
892 nvhdcp->a_ksv = get_aksv(hdmi);
893 nvhdcp->a_n = get_an(hdmi);
894 nvhdcp_vdbg("Aksv is 0x%016llx\n", nvhdcp->a_ksv);
895 nvhdcp_vdbg("An is 0x%016llx\n", nvhdcp->a_n);
896 if (verify_ksv(nvhdcp->a_ksv)) {
897 nvhdcp_err("Aksv verify failure! (0x%016llx)\n", nvhdcp->a_ksv);
898 goto disable;
899 }
900
901 /* write Ainfo to receiver - set 1.1 only if b_caps supports it */
902 e = nvhdcp_i2c_write8(nvhdcp, 0x15, b_caps & BCAPS_11);
903 if (e) {
904 nvhdcp_err("Ainfo write failure\n");
905 goto failure;
906 }
907
908 /* write An to receiver */
909 e = nvhdcp_i2c_write64(nvhdcp, 0x18, nvhdcp->a_n);
910 if (e) {
911 nvhdcp_err("An write failure\n");
912 goto failure;
913 }
914
915 nvhdcp_vdbg("wrote An = 0x%016llx\n", nvhdcp->a_n);
916
917 /* write Aksv to receiver - triggers auth sequence */
918 e = nvhdcp_i2c_write40(nvhdcp, 0x10, nvhdcp->a_ksv);
919 if (e) {
920 nvhdcp_err("Aksv write failure\n");
921 goto failure;
922 }
923
924 nvhdcp_vdbg("wrote Aksv = 0x%010llx\n", nvhdcp->a_ksv);
925
926 /* bail out if unplugged in the middle of negotiation */
927 if (!nvhdcp_is_plugged(nvhdcp))
928 goto lost_hdmi;
929
930 /* get Bksv from receiver */
931 e = nvhdcp_i2c_read40(nvhdcp, 0x00, &nvhdcp->b_ksv);
932 if (e) {
933 nvhdcp_err("Bksv read failure\n");
934 goto failure;
935 }
936 nvhdcp_vdbg("Bksv is 0x%016llx\n", nvhdcp->b_ksv);
937 if (verify_ksv(nvhdcp->b_ksv)) {
938 nvhdcp_err("Bksv verify failure!\n");
939 goto failure;
940 }
941
942 nvhdcp_vdbg("read Bksv = 0x%010llx from device\n", nvhdcp->b_ksv);
943
944 set_bksv(hdmi, nvhdcp->b_ksv, (b_caps & BCAPS_REPEATER));
945
946 nvhdcp_vdbg("loaded Bksv into controller\n");
947
948 e = wait_hdcp_ctrl(hdmi, R0_VALID, NULL);
949 if (e) {
950 nvhdcp_err("R0 read failure!\n");
951 goto failure;
952 }
953
954 nvhdcp_vdbg("R0 valid\n");
955
956 msleep(100); /* can't read R0' within 100ms of writing Aksv */
957
958 nvhdcp_vdbg("verifying links ...\n");
959
960 e = verify_link(nvhdcp, false);
961 if (e) {
962 nvhdcp_err("link verification failed err %d\n", e);
963 goto failure;
964 }
965
966 /* if repeater then get repeater info */
967 if (b_caps & BCAPS_REPEATER) {
968 e = get_repeater_info(nvhdcp);
969 if (e) {
970 nvhdcp_err("get repeater info failed\n");
971 goto failure;
972 }
973 }
974
975 tmp = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_RG_HDCP_CTRL);
976 tmp |= CRYPT_ENABLED;
977 if (b_caps & BCAPS_11) /* HDCP 1.1 ? */
978 tmp |= ONEONE_ENABLED;
979 tegra_hdmi_writel(hdmi, tmp, HDMI_NV_PDISP_RG_HDCP_CTRL);
980
981 nvhdcp_vdbg("CRYPT enabled\n");
982
983 nvhdcp->state = STATE_LINK_VERIFY;
984 nvhdcp_info("link verified!\n");
985
986 while (1) {
987 if (!nvhdcp_is_plugged(nvhdcp))
988 goto lost_hdmi;
989
990 if (nvhdcp->state != STATE_LINK_VERIFY)
991 goto failure;
992
993 e = verify_link(nvhdcp, true);
994 if (e) {
995 nvhdcp_err("link verification failed err %d\n", e);
996 goto failure;
997 }
998 mutex_unlock(&nvhdcp->lock);
999 wait_event_interruptible_timeout(wq_worker,
1000 !nvhdcp_is_plugged(nvhdcp), msecs_to_jiffies(1500));
1001 mutex_lock(&nvhdcp->lock);
1002
1003 }
1004
1005failure:
1006 nvhdcp->fail_count++;
1007 if(nvhdcp->fail_count > 5) {
1008 nvhdcp_err("nvhdcp failure - too many failures, giving up!\n");
1009 } else {
1010 nvhdcp_err("nvhdcp failure - renegotiating in 1 second\n");
1011 if (!nvhdcp_is_plugged(nvhdcp))
1012 goto lost_hdmi;
1013 queue_delayed_work(nvhdcp->downstream_wq, &nvhdcp->work,
1014 msecs_to_jiffies(1000));
1015 }
1016
1017lost_hdmi:
1018 nvhdcp->state = STATE_UNAUTHENTICATED;
1019 hdcp_ctrl_run(hdmi, 0);
1020
1021err:
1022 mutex_unlock(&nvhdcp->lock);
1023 return;
1024disable:
1025 nvhdcp->state = STATE_OFF;
1026 nvhdcp_set_plugged(nvhdcp, false);
1027 mutex_unlock(&nvhdcp->lock);
1028 return;
1029}
1030
1031static int tegra_nvhdcp_on(struct tegra_nvhdcp *nvhdcp)
1032{
1033 nvhdcp->state = STATE_UNAUTHENTICATED;
1034 if (nvhdcp_is_plugged(nvhdcp)) {
1035 nvhdcp->fail_count = 0;
1036 queue_delayed_work(nvhdcp->downstream_wq, &nvhdcp->work,
1037 msecs_to_jiffies(100));
1038 }
1039 return 0;
1040}
1041
1042static int tegra_nvhdcp_off(struct tegra_nvhdcp *nvhdcp)
1043{
1044 mutex_lock(&nvhdcp->lock);
1045 nvhdcp->state = STATE_OFF;
1046 nvhdcp_set_plugged(nvhdcp, false);
1047 mutex_unlock(&nvhdcp->lock);
1048 wake_up_interruptible(&wq_worker);
1049 flush_workqueue(nvhdcp->downstream_wq);
1050 return 0;
1051}
1052
1053void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd)
1054{
1055 nvhdcp_debug("hdmi hotplug detected (hpd = %d)\n", hpd);
1056
1057 if (hpd) {
1058 nvhdcp_set_plugged(nvhdcp, true);
1059 tegra_nvhdcp_on(nvhdcp);
1060 } else {
1061 tegra_nvhdcp_off(nvhdcp);
1062 }
1063}
1064
1065int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol)
1066{
1067 if (pol == TEGRA_NVHDCP_POLICY_ALWAYS_ON) {
1068 nvhdcp_info("using \"always on\" policy.\n");
1069 if (atomic_xchg(&nvhdcp->policy, pol) != pol) {
1070 /* policy changed, start working */
1071 tegra_nvhdcp_on(nvhdcp);
1072 }
1073 } else {
1074 /* unsupported policy */
1075 return -EINVAL;
1076 }
1077
1078 return 0;
1079}
1080
1081static int tegra_nvhdcp_renegotiate(struct tegra_nvhdcp *nvhdcp)
1082{
1083 mutex_lock(&nvhdcp->lock);
1084 nvhdcp->state = STATE_RENEGOTIATE;
1085 mutex_unlock(&nvhdcp->lock);
1086 tegra_nvhdcp_on(nvhdcp);
1087 return 0;
1088}
1089
1090void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp)
1091{
1092 if (!nvhdcp) return;
1093 tegra_nvhdcp_off(nvhdcp);
1094}
1095
1096void tegra_nvhdcp_resume(struct tegra_nvhdcp *nvhdcp)
1097{
1098 if (!nvhdcp) return;
1099 tegra_nvhdcp_renegotiate(nvhdcp);
1100}
1101
1102static long nvhdcp_dev_ioctl(struct file *filp,
1103 unsigned int cmd, unsigned long arg)
1104{
1105 struct tegra_nvhdcp *nvhdcp = filp->private_data;
1106 struct tegra_nvhdcp_packet *pkt;
1107 int e = -ENOTTY;
1108
1109 switch (cmd) {
1110 case TEGRAIO_NVHDCP_ON:
1111 return tegra_nvhdcp_on(nvhdcp);
1112
1113 case TEGRAIO_NVHDCP_OFF:
1114 return tegra_nvhdcp_off(nvhdcp);
1115
1116 case TEGRAIO_NVHDCP_SET_POLICY:
1117 return tegra_nvhdcp_set_policy(nvhdcp, arg);
1118
1119 case TEGRAIO_NVHDCP_READ_M:
1120 pkt = kmalloc(sizeof(*pkt), GFP_KERNEL);
1121 if (!pkt)
1122 return -ENOMEM;
1123 if (copy_from_user(pkt, (void __user *)arg, sizeof(*pkt))) {
1124 e = -EFAULT;
1125 goto kfree_pkt;
1126 }
1127 e = get_m_prime(nvhdcp, pkt);
1128 if (copy_to_user((void __user *)arg, pkt, sizeof(*pkt))) {
1129 e = -EFAULT;
1130 goto kfree_pkt;
1131 }
1132 kfree(pkt);
1133 return e;
1134
1135 case TEGRAIO_NVHDCP_READ_S:
1136 pkt = kmalloc(sizeof(*pkt), GFP_KERNEL);
1137 if (!pkt)
1138 return -ENOMEM;
1139 if (copy_from_user(pkt, (void __user *)arg, sizeof(*pkt))) {
1140 e = -EFAULT;
1141 goto kfree_pkt;
1142 }
1143 e = get_s_prime(nvhdcp, pkt);
1144 if (copy_to_user((void __user *)arg, pkt, sizeof(*pkt))) {
1145 e = -EFAULT;
1146 goto kfree_pkt;
1147 }
1148 kfree(pkt);
1149 return e;
1150
1151 case TEGRAIO_NVHDCP_RENEGOTIATE:
1152 e = tegra_nvhdcp_renegotiate(nvhdcp);
1153 break;
1154 }
1155
1156 return e;
1157kfree_pkt:
1158 kfree(pkt);
1159 return e;
1160}
1161
1162static int nvhdcp_dev_open(struct inode *inode, struct file *filp)
1163{
1164 struct miscdevice *miscdev = filp->private_data;
1165 struct tegra_nvhdcp *nvhdcp =
1166 container_of(miscdev, struct tegra_nvhdcp, miscdev);
1167 filp->private_data = nvhdcp;
1168 return 0;
1169}
1170
1171static int nvhdcp_dev_release(struct inode *inode, struct file *filp)
1172{
1173 filp->private_data = NULL;
1174 return 0;
1175}
1176
1177static const struct file_operations nvhdcp_fops = {
1178 .owner = THIS_MODULE,
1179 .llseek = no_llseek,
1180 .unlocked_ioctl = nvhdcp_dev_ioctl,
1181 .open = nvhdcp_dev_open,
1182 .release = nvhdcp_dev_release,
1183};
1184
1185/* we only support one AP right now, so should only call this once. */
1186struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi,
1187 int id, int bus)
1188{
1189 static struct tegra_nvhdcp *nvhdcp; /* prevent multiple calls */
1190 struct i2c_adapter *adapter;
1191 int e;
1192
1193 if (nvhdcp)
1194 return ERR_PTR(-EMFILE);
1195
1196 nvhdcp = kzalloc(sizeof(*nvhdcp), GFP_KERNEL);
1197 if (!nvhdcp)
1198 return ERR_PTR(-ENOMEM);
1199
1200 nvhdcp->id = id;
1201 snprintf(nvhdcp->name, sizeof(nvhdcp->name), "nvhdcp%u", id);
1202 nvhdcp->hdmi = hdmi;
1203 mutex_init(&nvhdcp->lock);
1204
1205 strlcpy(nvhdcp->info.type, nvhdcp->name, sizeof(nvhdcp->info.type));
1206 nvhdcp->bus = bus;
1207 nvhdcp->info.addr = 0x74 >> 1;
1208 nvhdcp->info.platform_data = nvhdcp;
1209 nvhdcp->fail_count = 0;
1210
1211 adapter = i2c_get_adapter(bus);
1212 if (!adapter) {
1213 nvhdcp_err("can't get adapter for bus %d\n", bus);
1214 e = -EBUSY;
1215 goto free_nvhdcp;
1216 }
1217
1218 nvhdcp->client = i2c_new_device(adapter, &nvhdcp->info);
1219 i2c_put_adapter(adapter);
1220
1221 if (!nvhdcp->client) {
1222 nvhdcp_err("can't create new device\n");
1223 e = -EBUSY;
1224 goto free_nvhdcp;
1225 }
1226
1227 nvhdcp->state = STATE_UNAUTHENTICATED;
1228
1229 nvhdcp->downstream_wq = create_singlethread_workqueue(nvhdcp->name);
1230 INIT_DELAYED_WORK(&nvhdcp->work, nvhdcp_downstream_worker);
1231
1232 nvhdcp->miscdev.minor = MISC_DYNAMIC_MINOR;
1233 nvhdcp->miscdev.name = nvhdcp->name;
1234 nvhdcp->miscdev.fops = &nvhdcp_fops;
1235
1236 e = misc_register(&nvhdcp->miscdev);
1237 if (e)
1238 goto free_workqueue;
1239
1240 nvhdcp_vdbg("%s(): created misc device %s\n", __func__, nvhdcp->name);
1241
1242 return nvhdcp;
1243free_workqueue:
1244 destroy_workqueue(nvhdcp->downstream_wq);
1245 i2c_release_client(nvhdcp->client);
1246free_nvhdcp:
1247 kfree(nvhdcp);
1248 nvhdcp_err("unable to create device.\n");
1249 return ERR_PTR(e);
1250}
1251
1252void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp)
1253{
1254 misc_deregister(&nvhdcp->miscdev);
1255 tegra_nvhdcp_off(nvhdcp);
1256 destroy_workqueue(nvhdcp->downstream_wq);
1257 i2c_release_client(nvhdcp->client);
1258 kfree(nvhdcp);
1259}
diff --git a/drivers/video/tegra/dc/nvhdcp.h b/drivers/video/tegra/dc/nvhdcp.h
new file mode 100644
index 00000000000..90ea0be36d1
--- /dev/null
+++ b/drivers/video/tegra/dc/nvhdcp.h
@@ -0,0 +1,46 @@
1/*
2 * drivers/video/tegra/dc/nvhdcp.h
3 *
4 * Copyright (c) 2010-2011, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __DRIVERS_VIDEO_TEGRA_DC_NVHDCP_H
18#define __DRIVERS_VIDEO_TEGRA_DC_NVHDCP_H
19#include <video/nvhdcp.h>
20
21struct tegra_nvhdcp;
22#ifdef CONFIG_TEGRA_NVHDCP
23void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd);
24int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol);
25void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp);
26void tegra_nvhdcp_resume(struct tegra_nvhdcp *nvhdcp);
27struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi,
28 int id, int bus);
29void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp);
30#else
31inline void tegra_nvhdcp_set_plug(struct tegra_nvhdcp *nvhdcp, bool hpd) { }
32inline int tegra_nvhdcp_set_policy(struct tegra_nvhdcp *nvhdcp, int pol)
33{
34 return 0;
35}
36inline void tegra_nvhdcp_suspend(struct tegra_nvhdcp *nvhdcp) { }
37inline void tegra_nvhdcp_resume(struct tegra_nvhdcp *nvhdcp) { }
38inline struct tegra_nvhdcp *tegra_nvhdcp_create(struct tegra_dc_hdmi_data *hdmi,
39 int id, int bus)
40{
41 return NULL;
42}
43inline void tegra_nvhdcp_destroy(struct tegra_nvhdcp *nvhdcp) { }
44#endif
45
46#endif
diff --git a/drivers/video/tegra/dc/nvsd.c b/drivers/video/tegra/dc/nvsd.c
new file mode 100644
index 00000000000..a2f3ece6ae7
--- /dev/null
+++ b/drivers/video/tegra/dc/nvsd.c
@@ -0,0 +1,906 @@
1/*
2 * drivers/video/tegra/dc/nvsd.c
3 *
4 * Copyright (c) 2010-2012, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#include <linux/kernel.h>
18#include <mach/dc.h>
19#include <linux/types.h>
20#include <linux/string.h>
21#include <linux/slab.h>
22#include <linux/backlight.h>
23#include <linux/platform_device.h>
24
25#include "dc_reg.h"
26#include "dc_priv.h"
27#include "nvsd.h"
28
29/* Elements for sysfs access */
30#define NVSD_ATTR(__name) static struct kobj_attribute nvsd_attr_##__name = \
31 __ATTR(__name, S_IRUGO|S_IWUSR, nvsd_settings_show, nvsd_settings_store)
32#define NVSD_ATTRS_ENTRY(__name) (&nvsd_attr_##__name.attr)
33#define IS_NVSD_ATTR(__name) (attr == &nvsd_attr_##__name)
34
35static ssize_t nvsd_settings_show(struct kobject *kobj,
36 struct kobj_attribute *attr, char *buf);
37
38static ssize_t nvsd_settings_store(struct kobject *kobj,
39 struct kobj_attribute *attr, const char *buf, size_t count);
40
41static ssize_t nvsd_registers_show(struct kobject *kobj,
42 struct kobj_attribute *attr, char *buf);
43
44NVSD_ATTR(enable);
45NVSD_ATTR(aggressiveness);
46NVSD_ATTR(phase_in_settings);
47NVSD_ATTR(phase_in_adjustments);
48NVSD_ATTR(bin_width);
49NVSD_ATTR(hw_update_delay);
50NVSD_ATTR(use_vid_luma);
51NVSD_ATTR(coeff);
52NVSD_ATTR(blp_time_constant);
53NVSD_ATTR(blp_step);
54NVSD_ATTR(fc_time_limit);
55NVSD_ATTR(fc_threshold);
56NVSD_ATTR(lut);
57NVSD_ATTR(bltf);
58static struct kobj_attribute nvsd_attr_registers =
59 __ATTR(registers, S_IRUGO, nvsd_registers_show, NULL);
60
61static struct attribute *nvsd_attrs[] = {
62 NVSD_ATTRS_ENTRY(enable),
63 NVSD_ATTRS_ENTRY(aggressiveness),
64 NVSD_ATTRS_ENTRY(phase_in_settings),
65 NVSD_ATTRS_ENTRY(phase_in_adjustments),
66 NVSD_ATTRS_ENTRY(bin_width),
67 NVSD_ATTRS_ENTRY(hw_update_delay),
68 NVSD_ATTRS_ENTRY(use_vid_luma),
69 NVSD_ATTRS_ENTRY(coeff),
70 NVSD_ATTRS_ENTRY(blp_time_constant),
71 NVSD_ATTRS_ENTRY(blp_step),
72 NVSD_ATTRS_ENTRY(fc_time_limit),
73 NVSD_ATTRS_ENTRY(fc_threshold),
74 NVSD_ATTRS_ENTRY(lut),
75 NVSD_ATTRS_ENTRY(bltf),
76 NVSD_ATTRS_ENTRY(registers),
77 NULL,
78};
79
80static struct attribute_group nvsd_attr_group = {
81 .attrs = nvsd_attrs,
82};
83
84static struct kobject *nvsd_kobj;
85
86/* shared brightness variable */
87static atomic_t *sd_brightness = NULL;
88/* shared boolean for manual K workaround */
89static atomic_t man_k_until_blank = ATOMIC_INIT(0);
90
91static u8 nvsd_get_bw_idx(struct tegra_dc_sd_settings *settings)
92{
93 u8 bw;
94
95 switch (settings->bin_width) {
96 default:
97 case -1:
98 /* A -1 bin-width indicates 'automatic'
99 based upon aggressiveness. */
100 settings->bin_width = -1;
101 switch (settings->aggressiveness) {
102 default:
103 case 0:
104 case 1:
105 bw = SD_BIN_WIDTH_ONE;
106 break;
107 case 2:
108 case 3:
109 case 4:
110 bw = SD_BIN_WIDTH_TWO;
111 break;
112 case 5:
113 bw = SD_BIN_WIDTH_FOUR;
114 break;
115 }
116 break;
117 case 1:
118 bw = SD_BIN_WIDTH_ONE;
119 break;
120 case 2:
121 bw = SD_BIN_WIDTH_TWO;
122 break;
123 case 4:
124 bw = SD_BIN_WIDTH_FOUR;
125 break;
126 case 8:
127 bw = SD_BIN_WIDTH_EIGHT;
128 break;
129 }
130 return bw >> 3;
131
132}
133
134static bool nvsd_phase_in_adjustments(struct tegra_dc *dc,
135 struct tegra_dc_sd_settings *settings)
136{
137 u8 step, cur_sd_brightness;
138 u16 target_k, cur_k;
139 u32 man_k, val;
140
141 cur_sd_brightness = atomic_read(sd_brightness);
142
143 target_k = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
144 target_k = SD_HW_K_R(target_k);
145 cur_k = tegra_dc_readl(dc, DC_DISP_SD_MAN_K_VALUES);
146 cur_k = SD_HW_K_R(cur_k);
147
148 /* read brightness value */
149 val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL);
150 val = SD_BLC_BRIGHTNESS(val);
151
152 step = settings->phase_adj_step;
153 if (cur_sd_brightness != val || target_k != cur_k) {
154 if (!step)
155 step = ADJ_PHASE_STEP;
156
157 /* Phase in Backlight and Pixel K
158 every ADJ_PHASE_STEP frames*/
159 if ((step-- & ADJ_PHASE_STEP) == ADJ_PHASE_STEP) {
160
161 if (val != cur_sd_brightness)
162 val > cur_sd_brightness ?
163 (cur_sd_brightness++) :
164 (cur_sd_brightness--);
165
166 if (target_k != cur_k) {
167 if (target_k > cur_k)
168 cur_k += K_STEP;
169 else
170 cur_k -= K_STEP;
171 }
172
173 /* Set manual k value */
174 man_k = SD_MAN_K_R(cur_k) |
175 SD_MAN_K_G(cur_k) | SD_MAN_K_B(cur_k);
176 tegra_dc_writel(dc, man_k, DC_DISP_SD_MAN_K_VALUES);
177 /* Set manual brightness value */
178 atomic_set(sd_brightness, cur_sd_brightness);
179 }
180 settings->phase_adj_step = step;
181 return true;
182 } else
183 return false;
184}
185
186/* phase in the luts based on the current and max step */
187static void nvsd_phase_in_luts(struct tegra_dc_sd_settings *settings,
188 struct tegra_dc *dc)
189{
190 u32 val;
191 u8 bw_idx;
192 int i;
193 u16 phase_settings_step = settings->phase_settings_step;
194 u16 num_phase_in_steps = settings->num_phase_in_steps;
195
196 bw_idx = nvsd_get_bw_idx(settings);
197
198 /* Phase in Final LUT */
199 for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
200 val = SD_LUT_R((settings->lut[bw_idx][i].r *
201 phase_settings_step)/num_phase_in_steps) |
202 SD_LUT_G((settings->lut[bw_idx][i].g *
203 phase_settings_step)/num_phase_in_steps) |
204 SD_LUT_B((settings->lut[bw_idx][i].b *
205 phase_settings_step)/num_phase_in_steps);
206
207 tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));
208 }
209 /* Phase in Final BLTF */
210 for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
211 val = SD_BL_TF_POINT_0(255-((255-settings->bltf[bw_idx][i][0])
212 * phase_settings_step)/num_phase_in_steps) |
213 SD_BL_TF_POINT_1(255-((255-settings->bltf[bw_idx][i][1])
214 * phase_settings_step)/num_phase_in_steps) |
215 SD_BL_TF_POINT_2(255-((255-settings->bltf[bw_idx][i][2])
216 * phase_settings_step)/num_phase_in_steps) |
217 SD_BL_TF_POINT_3(255-((255-settings->bltf[bw_idx][i][3])
218 * phase_settings_step)/num_phase_in_steps);
219
220 tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
221 }
222}
223
224/* handle the commands that may be invoked for phase_in_settings */
225static void nvsd_cmd_handler(struct tegra_dc_sd_settings *settings,
226 struct tegra_dc *dc)
227{
228 u32 val;
229 u8 bw_idx, bw;
230
231 if (settings->cmd & ENABLE) {
232 settings->phase_settings_step++;
233 if (settings->phase_settings_step >=
234 settings->num_phase_in_steps)
235 settings->cmd &= ~ENABLE;
236
237 nvsd_phase_in_luts(settings, dc);
238 }
239 if (settings->cmd & DISABLE) {
240 settings->phase_settings_step--;
241 nvsd_phase_in_luts(settings, dc);
242 if (settings->phase_settings_step == 0) {
243 /* finish up aggressiveness phase in */
244 if (settings->cmd & AGG_CHG)
245 settings->aggressiveness = settings->final_agg;
246 settings->cmd = NO_CMD;
247 settings->enable = 0;
248 nvsd_init(dc, settings);
249 }
250 }
251 if (settings->cmd & AGG_CHG) {
252 if (settings->aggressiveness == settings->final_agg)
253 settings->cmd &= ~AGG_CHG;
254 if ((settings->cur_agg_step++ & (STEPS_PER_AGG_CHG - 1)) == 0) {
255 settings->final_agg > settings->aggressiveness ?
256 settings->aggressiveness++ :
257 settings->aggressiveness--;
258
259 /* Update aggressiveness value in HW */
260 val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
261 val &= ~SD_AGGRESSIVENESS(0x7);
262 val |= SD_AGGRESSIVENESS(settings->aggressiveness);
263
264 /* Adjust bin_width for automatic setting */
265 if (settings->bin_width == -1) {
266 bw_idx = nvsd_get_bw_idx(settings);
267
268 bw = bw_idx << 3;
269
270 val &= ~SD_BIN_WIDTH_MASK;
271 val |= bw;
272 }
273 tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
274
275 nvsd_phase_in_luts(settings, dc);
276 }
277 }
278}
279
280static bool nvsd_update_enable(struct tegra_dc_sd_settings *settings,
281 int enable_val)
282{
283
284 if (enable_val != 1 && enable_val != 0)
285 return false;
286
287 if (!settings->cmd && settings->enable != enable_val) {
288 settings->num_phase_in_steps =
289 STEPS_PER_AGG_LVL*settings->aggressiveness;
290 settings->phase_settings_step = enable_val ?
291 0 : settings->num_phase_in_steps;
292 }
293
294 if (settings->enable != enable_val || settings->cmd & DISABLE) {
295 settings->cmd &= ~(ENABLE | DISABLE);
296 if (!settings->enable && enable_val)
297 settings->cmd |= PHASE_IN;
298 settings->cmd |= enable_val ? ENABLE : DISABLE;
299 return true;
300 }
301
302 return false;
303}
304
305static bool nvsd_update_agg(struct tegra_dc_sd_settings *settings, int agg_val)
306{
307 int i;
308 int pri_lvl = SD_AGG_PRI_LVL(agg_val);
309 int agg_lvl = SD_GET_AGG(agg_val);
310 struct tegra_dc_sd_agg_priorities *sd_agg_priorities =
311 &settings->agg_priorities;
312
313 if (agg_lvl > 5 || agg_lvl < 0)
314 return false;
315 else if (agg_lvl == 0 && pri_lvl == 0)
316 return false;
317
318 if (pri_lvl >= 0 && pri_lvl < 4)
319 sd_agg_priorities->agg[pri_lvl] = agg_lvl;
320
321 for (i = NUM_AGG_PRI_LVLS - 1; i >= 0; i--) {
322 if (sd_agg_priorities->agg[i])
323 break;
324 }
325
326 sd_agg_priorities->pri_lvl = i;
327 pri_lvl = i;
328 agg_lvl = sd_agg_priorities->agg[i];
329
330 if (settings->phase_in_settings && settings->enable &&
331 settings->aggressiveness != agg_lvl) {
332
333 settings->final_agg = agg_lvl;
334 settings->cmd |= AGG_CHG;
335 settings->cur_agg_step = 0;
336 return true;
337 } else if (settings->aggressiveness != agg_lvl) {
338 settings->aggressiveness = agg_lvl;
339 return true;
340 }
341
342 return false;
343}
344
345/* Functional initialization */
346void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings)
347{
348 u32 i = 0;
349 u32 val = 0;
350 u32 bw_idx = 0;
351 /* TODO: check if HW says SD's available */
352
353 /* If SD's not present or disabled, clear the register and return. */
354 if (!settings || settings->enable == 0) {
355 /* clear the brightness val, too. */
356 if (sd_brightness)
357 atomic_set(sd_brightness, 255);
358
359 sd_brightness = NULL;
360
361 if (settings)
362 settings->phase_settings_step = 0;
363 tegra_dc_writel(dc, 0, DC_DISP_SD_CONTROL);
364 return;
365 }
366
367 dev_dbg(&dc->ndev->dev, "NVSD Init:\n");
368
369 /* init agg_priorities */
370 if (!settings->agg_priorities.agg[0])
371 settings->agg_priorities.agg[0] = settings->aggressiveness;
372
373 /* WAR: Settings will not be valid until the next flip.
374 * Thus, set manual K to either HW's current value (if
375 * we're already enabled) or a non-effective value (if
376 * we're about to enable). */
377 val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
378
379 if (val & SD_ENABLE_NORMAL)
380 i = tegra_dc_readl(dc, DC_DISP_SD_HW_K_VALUES);
381 else
382 i = 0; /* 0 values for RGB = 1.0, i.e. non-affected */
383
384 tegra_dc_writel(dc, i, DC_DISP_SD_MAN_K_VALUES);
385 /* Enable manual correction mode here so that changing the
386 * settings won't immediately impact display dehavior. */
387 val |= SD_CORRECTION_MODE_MAN;
388 tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
389
390 bw_idx = nvsd_get_bw_idx(settings);
391
392 /* Write LUT */
393 if (!settings->cmd) {
394 dev_dbg(&dc->ndev->dev, " LUT:\n");
395
396 for (i = 0; i < DC_DISP_SD_LUT_NUM; i++) {
397 val = SD_LUT_R(settings->lut[bw_idx][i].r) |
398 SD_LUT_G(settings->lut[bw_idx][i].g) |
399 SD_LUT_B(settings->lut[bw_idx][i].b);
400 tegra_dc_writel(dc, val, DC_DISP_SD_LUT(i));
401
402 dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
403 }
404 }
405
406 /* Write BL TF */
407 if (!settings->cmd) {
408 dev_dbg(&dc->ndev->dev, " BL_TF:\n");
409
410 for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
411 val = SD_BL_TF_POINT_0(settings->bltf[bw_idx][i][0]) |
412 SD_BL_TF_POINT_1(settings->bltf[bw_idx][i][1]) |
413 SD_BL_TF_POINT_2(settings->bltf[bw_idx][i][2]) |
414 SD_BL_TF_POINT_3(settings->bltf[bw_idx][i][3]);
415
416 tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
417
418 dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
419 }
420 } else if ((settings->cmd & PHASE_IN)) {
421 settings->cmd &= ~PHASE_IN;
422 /* Write NO_OP values for BLTF */
423 for (i = 0; i < DC_DISP_SD_BL_TF_NUM; i++) {
424 val = SD_BL_TF_POINT_0(0xFF) |
425 SD_BL_TF_POINT_1(0xFF) |
426 SD_BL_TF_POINT_2(0xFF) |
427 SD_BL_TF_POINT_3(0xFF);
428
429 tegra_dc_writel(dc, val, DC_DISP_SD_BL_TF(i));
430
431 dev_dbg(&dc->ndev->dev, " %d: 0x%08x\n", i, val);
432 }
433 }
434
435 /* Set step correctly on init */
436 if (!settings->cmd && settings->phase_in_settings) {
437 settings->num_phase_in_steps = STEPS_PER_AGG_LVL *
438 settings->aggressiveness;
439 settings->phase_settings_step = settings->enable ?
440 settings->num_phase_in_steps : 0;
441 }
442
443 /* Write Coeff */
444 val = SD_CSC_COEFF_R(settings->coeff.r) |
445 SD_CSC_COEFF_G(settings->coeff.g) |
446 SD_CSC_COEFF_B(settings->coeff.b);
447 tegra_dc_writel(dc, val, DC_DISP_SD_CSC_COEFF);
448 dev_dbg(&dc->ndev->dev, " COEFF: 0x%08x\n", val);
449
450 /* Write BL Params */
451 val = SD_BLP_TIME_CONSTANT(settings->blp.time_constant) |
452 SD_BLP_STEP(settings->blp.step);
453 tegra_dc_writel(dc, val, DC_DISP_SD_BL_PARAMETERS);
454 dev_dbg(&dc->ndev->dev, " BLP: 0x%08x\n", val);
455
456 /* Write Auto/Manual PWM */
457 val = (settings->use_auto_pwm) ? SD_BLC_MODE_AUTO : SD_BLC_MODE_MAN;
458 tegra_dc_writel(dc, val, DC_DISP_SD_BL_CONTROL);
459 dev_dbg(&dc->ndev->dev, " BL_CONTROL: 0x%08x\n", val);
460
461 /* Write Flicker Control */
462 val = SD_FC_TIME_LIMIT(settings->fc.time_limit) |
463 SD_FC_THRESHOLD(settings->fc.threshold);
464 tegra_dc_writel(dc, val, DC_DISP_SD_FLICKER_CONTROL);
465 dev_dbg(&dc->ndev->dev, " FLICKER_CONTROL: 0x%08x\n", val);
466
467 /* Manage SD Control */
468 val = 0;
469 /* Stay in manual correction mode until the next flip. */
470 val |= SD_CORRECTION_MODE_MAN;
471 /* Enable / One-Shot */
472 val |= (settings->enable == 2) ?
473 (SD_ENABLE_ONESHOT | SD_ONESHOT_ENABLE) :
474 SD_ENABLE_NORMAL;
475 /* HW Update Delay */
476 val |= SD_HW_UPDATE_DLY(settings->hw_update_delay);
477 /* Video Luma */
478 val |= (settings->use_vid_luma) ? SD_USE_VID_LUMA : 0;
479 /* Aggressiveness */
480 val |= SD_AGGRESSIVENESS(settings->aggressiveness);
481 /* Bin Width (value derived from bw_idx) */
482 val |= bw_idx << 3;
483 /* Finally, Write SD Control */
484 tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
485 dev_dbg(&dc->ndev->dev, " SD_CONTROL: 0x%08x\n", val);
486
487 /* set the brightness pointer */
488 sd_brightness = settings->sd_brightness;
489
490 /* note that we're in manual K until the next flip */
491 atomic_set(&man_k_until_blank, 1);
492}
493
494/* Periodic update */
495bool nvsd_update_brightness(struct tegra_dc *dc)
496{
497 u32 val = 0;
498 int cur_sd_brightness;
499 struct tegra_dc_sd_settings *settings = dc->out->sd_settings;
500
501 if (sd_brightness) {
502 if (atomic_read(&man_k_until_blank) &&
503 !settings->phase_in_adjustments) {
504 val = tegra_dc_readl(dc, DC_DISP_SD_CONTROL);
505 val &= ~SD_CORRECTION_MODE_MAN;
506 tegra_dc_writel(dc, val, DC_DISP_SD_CONTROL);
507 atomic_set(&man_k_until_blank, 0);
508 }
509
510 if (settings->cmd)
511 nvsd_cmd_handler(settings, dc);
512
513 /* nvsd_cmd_handler may turn off didim */
514 if (!settings->enable)
515 return true;
516
517 cur_sd_brightness = atomic_read(sd_brightness);
518
519 /* read brightness value */
520 val = tegra_dc_readl(dc, DC_DISP_SD_BL_CONTROL);
521 val = SD_BLC_BRIGHTNESS(val);
522
523 if (settings->phase_in_adjustments) {
524 return nvsd_phase_in_adjustments(dc, settings);
525 } else if (val != (u32)cur_sd_brightness) {
526 /* set brightness value and note the update */
527 atomic_set(sd_brightness, (int)val);
528 return true;
529 }
530 }
531
532 /* No update needed. */
533 return false;
534}
535
536static ssize_t nvsd_lut_show(struct tegra_dc_sd_settings *sd_settings,
537 char *buf, ssize_t res)
538{
539 u32 i;
540 u32 j;
541
542 for (i = 0; i < NUM_BIN_WIDTHS; i++) {
543 res += snprintf(buf + res, PAGE_SIZE - res,
544 "Bin Width: %d\n", 1 << i);
545
546 for (j = 0; j < DC_DISP_SD_LUT_NUM; j++) {
547 res += snprintf(buf + res,
548 PAGE_SIZE - res,
549 "%d: R: %3d / G: %3d / B: %3d\n",
550 j,
551 sd_settings->lut[i][j].r,
552 sd_settings->lut[i][j].g,
553 sd_settings->lut[i][j].b);
554 }
555 }
556 return res;
557}
558
559static ssize_t nvsd_bltf_show(struct tegra_dc_sd_settings *sd_settings,
560 char *buf, ssize_t res)
561{
562 u32 i;
563 u32 j;
564
565 for (i = 0; i < NUM_BIN_WIDTHS; i++) {
566 res += snprintf(buf + res, PAGE_SIZE - res,
567 "Bin Width: %d\n", 1 << i);
568
569 for (j = 0; j < DC_DISP_SD_BL_TF_NUM; j++) {
570 res += snprintf(buf + res,
571 PAGE_SIZE - res,
572 "%d: 0: %3d / 1: %3d / 2: %3d / 3: %3d\n",
573 j,
574 sd_settings->bltf[i][j][0],
575 sd_settings->bltf[i][j][1],
576 sd_settings->bltf[i][j][2],
577 sd_settings->bltf[i][j][3]);
578 }
579 }
580 return res;
581}
582
583/* Sysfs accessors */
584static ssize_t nvsd_settings_show(struct kobject *kobj,
585 struct kobj_attribute *attr, char *buf)
586{
587 struct device *dev = container_of((kobj->parent), struct device, kobj);
588 struct nvhost_device *ndev = to_nvhost_device(dev);
589 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
590 struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings;
591 ssize_t res = 0;
592
593 if (sd_settings) {
594 if (IS_NVSD_ATTR(enable))
595 res = snprintf(buf, PAGE_SIZE, "%d\n",
596 sd_settings->enable);
597 else if (IS_NVSD_ATTR(aggressiveness))
598 res = snprintf(buf, PAGE_SIZE, "%d\n",
599 sd_settings->aggressiveness);
600 else if (IS_NVSD_ATTR(phase_in_settings))
601 res = snprintf(buf, PAGE_SIZE, "%d\n",
602 sd_settings->phase_in_settings);
603 else if (IS_NVSD_ATTR(phase_in_adjustments))
604 res = snprintf(buf, PAGE_SIZE, "%d\n",
605 sd_settings->phase_in_adjustments);
606 else if (IS_NVSD_ATTR(bin_width))
607 res = snprintf(buf, PAGE_SIZE, "%d\n",
608 sd_settings->bin_width);
609 else if (IS_NVSD_ATTR(hw_update_delay))
610 res = snprintf(buf, PAGE_SIZE, "%d\n",
611 sd_settings->hw_update_delay);
612 else if (IS_NVSD_ATTR(use_vid_luma))
613 res = snprintf(buf, PAGE_SIZE, "%d\n",
614 sd_settings->use_vid_luma);
615 else if (IS_NVSD_ATTR(coeff))
616 res = snprintf(buf, PAGE_SIZE,
617 "R: %d / G: %d / B: %d\n",
618 sd_settings->coeff.r,
619 sd_settings->coeff.g,
620 sd_settings->coeff.b);
621 else if (IS_NVSD_ATTR(blp_time_constant))
622 res = snprintf(buf, PAGE_SIZE, "%d\n",
623 sd_settings->blp.time_constant);
624 else if (IS_NVSD_ATTR(blp_step))
625 res = snprintf(buf, PAGE_SIZE, "%d\n",
626 sd_settings->blp.step);
627 else if (IS_NVSD_ATTR(fc_time_limit))
628 res = snprintf(buf, PAGE_SIZE, "%d\n",
629 sd_settings->fc.time_limit);
630 else if (IS_NVSD_ATTR(fc_threshold))
631 res = snprintf(buf, PAGE_SIZE, "%d\n",
632 sd_settings->fc.threshold);
633 else if (IS_NVSD_ATTR(lut))
634 res = nvsd_lut_show(sd_settings, buf, res);
635 else if (IS_NVSD_ATTR(bltf))
636 res = nvsd_bltf_show(sd_settings, buf, res);
637 else
638 res = -EINVAL;
639 } else {
640 /* This shouldn't be reachable. But just in case... */
641 res = -EINVAL;
642 }
643
644 return res;
645}
646
647#define nvsd_check_and_update(_min, _max, _varname) { \
648 int val = simple_strtol(buf, NULL, 10); \
649 if (val >= _min && val <= _max) { \
650 sd_settings->_varname = val; \
651 settings_updated = true; \
652 } }
653
654#define nvsd_get_multi(_ele, _num, _act, _min, _max) { \
655 char *b, *c, *orig_b; \
656 b = orig_b = kstrdup(buf, GFP_KERNEL); \
657 for (_act = 0; _act < _num; _act++) { \
658 if (!b) \
659 break; \
660 b = strim(b); \
661 c = strsep(&b, " "); \
662 if (!strlen(c)) \
663 break; \
664 _ele[_act] = simple_strtol(c, NULL, 10); \
665 if (_ele[_act] < _min || _ele[_act] > _max) \
666 break; \
667 } \
668 if (orig_b) \
669 kfree(orig_b); \
670}
671
672static int nvsd_lut_store(struct tegra_dc_sd_settings *sd_settings,
673 const char *buf)
674{
675 int ele[3 * DC_DISP_SD_LUT_NUM * NUM_BIN_WIDTHS];
676 int i = 0;
677 int j = 0;
678 int num = 3 * DC_DISP_SD_LUT_NUM * NUM_BIN_WIDTHS;
679
680 nvsd_get_multi(ele, num, i, 0, 255);
681
682 if (i != num)
683 return -EINVAL;
684
685 for (i = 0; i < NUM_BIN_WIDTHS; i++) {
686 for (j = 0; j < DC_DISP_SD_LUT_NUM; j++) {
687 sd_settings->lut[i][j].r =
688 ele[i * NUM_BIN_WIDTHS + j * 3 + 0];
689 sd_settings->lut[i][j].g =
690 ele[i * NUM_BIN_WIDTHS + j * 3 + 1];
691 sd_settings->lut[i][j].b =
692 ele[i * NUM_BIN_WIDTHS + j * 3 + 2];
693 }
694 }
695 return 0;
696}
697
698static int nvsd_bltf_store(struct tegra_dc_sd_settings *sd_settings,
699 const char *buf)
700{
701 int ele[4 * DC_DISP_SD_BL_TF_NUM * NUM_BIN_WIDTHS];
702 int i = 0, j = 0, num = ARRAY_SIZE(ele);
703
704 nvsd_get_multi(ele, num, i, 0, 255);
705
706 if (i != num)
707 return -EINVAL;
708
709 for (i = 0; i < NUM_BIN_WIDTHS; i++) {
710 for (j = 0; j < DC_DISP_SD_BL_TF_NUM; j++) {
711 size_t base = (i * NUM_BIN_WIDTHS *
712 DC_DISP_SD_BL_TF_NUM) + (j * 4);
713 sd_settings->bltf[i][j][0] = ele[base + 0];
714 sd_settings->bltf[i][j][1] = ele[base + 1];
715 sd_settings->bltf[i][j][2] = ele[base + 2];
716 sd_settings->bltf[i][j][3] = ele[base + 3];
717 }
718 }
719
720 return 0;
721}
722
723static ssize_t nvsd_settings_store(struct kobject *kobj,
724 struct kobj_attribute *attr, const char *buf, size_t count)
725{
726 struct device *dev = container_of((kobj->parent), struct device, kobj);
727 struct nvhost_device *ndev = to_nvhost_device(dev);
728 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
729 struct tegra_dc_sd_settings *sd_settings = dc->out->sd_settings;
730 ssize_t res = count;
731 bool settings_updated = false;
732 long int result;
733 int err;
734
735 if (sd_settings) {
736 if (IS_NVSD_ATTR(enable)) {
737 if (sd_settings->phase_in_settings) {
738 err = strict_strtol(buf, 10, &result);
739 if (err)
740 return err;
741
742 if (nvsd_update_enable(sd_settings, result))
743 nvsd_check_and_update(1, 1, enable);
744
745 } else {
746 nvsd_check_and_update(0, 1, enable);
747 }
748 } else if (IS_NVSD_ATTR(aggressiveness)) {
749 err = strict_strtol(buf, 10, &result);
750 if (err)
751 return err;
752
753 if (nvsd_update_agg(sd_settings, result)
754 && !sd_settings->phase_in_settings)
755 settings_updated = true;
756
757 } else if (IS_NVSD_ATTR(phase_in_settings)) {
758 nvsd_check_and_update(0, 1, phase_in_settings);
759 } else if (IS_NVSD_ATTR(phase_in_adjustments)) {
760 nvsd_check_and_update(0, 1, phase_in_adjustments);
761 } else if (IS_NVSD_ATTR(bin_width)) {
762 nvsd_check_and_update(0, 8, bin_width);
763 } else if (IS_NVSD_ATTR(hw_update_delay)) {
764 nvsd_check_and_update(0, 2, hw_update_delay);
765 } else if (IS_NVSD_ATTR(use_vid_luma)) {
766 nvsd_check_and_update(0, 1, use_vid_luma);
767 } else if (IS_NVSD_ATTR(coeff)) {
768 int ele[3], i = 0, num = 3;
769 nvsd_get_multi(ele, num, i, 0, 15);
770
771 if (i == num) {
772 sd_settings->coeff.r = ele[0];
773 sd_settings->coeff.g = ele[1];
774 sd_settings->coeff.b = ele[2];
775 settings_updated = true;
776 } else {
777 res = -EINVAL;
778 }
779 } else if (IS_NVSD_ATTR(blp_time_constant)) {
780 nvsd_check_and_update(0, 1024, blp.time_constant);
781 } else if (IS_NVSD_ATTR(blp_step)) {
782 nvsd_check_and_update(0, 255, blp.step);
783 } else if (IS_NVSD_ATTR(fc_time_limit)) {
784 nvsd_check_and_update(0, 255, fc.time_limit);
785 } else if (IS_NVSD_ATTR(fc_threshold)) {
786 nvsd_check_and_update(0, 255, fc.threshold);
787 } else if (IS_NVSD_ATTR(lut)) {
788 if (nvsd_lut_store(sd_settings, buf))
789 res = -EINVAL;
790 else
791 settings_updated = true;
792 } else if (IS_NVSD_ATTR(bltf)) {
793 if (nvsd_bltf_store(sd_settings, buf))
794 res = -EINVAL;
795 else
796 settings_updated = true;
797 } else {
798 res = -EINVAL;
799 }
800
801 /* Re-init if our settings were updated. */
802 if (settings_updated) {
803 mutex_lock(&dc->lock);
804 if (!dc->enabled) {
805 mutex_unlock(&dc->lock);
806 return -ENODEV;
807 }
808 mutex_unlock(&dc->lock);
809
810 nvsd_init(dc, sd_settings);
811
812 /* Update backlight state IFF we're disabling! */
813 if (!sd_settings->enable && sd_settings->bl_device) {
814 /* Do the actual brightness update outside of
815 * the mutex */
816 struct platform_device *pdev =
817 sd_settings->bl_device;
818 struct backlight_device *bl =
819 platform_get_drvdata(pdev);
820
821 if (bl)
822 backlight_update_status(bl);
823 }
824 }
825 } else {
826 /* This shouldn't be reachable. But just in case... */
827 res = -EINVAL;
828 }
829
830 return res;
831}
832
833#define NVSD_PRINT_REG(__name) { \
834 u32 val = tegra_dc_readl(dc, __name); \
835 res += snprintf(buf + res, PAGE_SIZE - res, #__name ": 0x%08x\n", \
836 val); \
837}
838
839#define NVSD_PRINT_REG_ARRAY(__name) { \
840 u32 val = 0, i = 0; \
841 res += snprintf(buf + res, PAGE_SIZE - res, #__name ":\n"); \
842 for (i = 0; i < __name##_NUM; i++) { \
843 val = tegra_dc_readl(dc, __name(i)); \
844 res += snprintf(buf + res, PAGE_SIZE - res, " %d: 0x%08x\n", \
845 i, val); \
846 } \
847}
848
849static ssize_t nvsd_registers_show(struct kobject *kobj,
850 struct kobj_attribute *attr, char *buf)
851{
852 struct device *dev = container_of((kobj->parent), struct device, kobj);
853 struct nvhost_device *ndev = to_nvhost_device(dev);
854 struct tegra_dc *dc = nvhost_get_drvdata(ndev);
855 ssize_t res = 0;
856
857 mutex_lock(&dc->lock);
858 if (!dc->enabled) {
859 mutex_unlock(&dc->lock);
860 return -ENODEV;
861 }
862
863 mutex_unlock(&dc->lock);
864 NVSD_PRINT_REG(DC_DISP_SD_CONTROL);
865 NVSD_PRINT_REG(DC_DISP_SD_CSC_COEFF);
866 NVSD_PRINT_REG_ARRAY(DC_DISP_SD_LUT);
867 NVSD_PRINT_REG(DC_DISP_SD_FLICKER_CONTROL);
868 NVSD_PRINT_REG(DC_DISP_SD_PIXEL_COUNT);
869 NVSD_PRINT_REG_ARRAY(DC_DISP_SD_HISTOGRAM);
870 NVSD_PRINT_REG(DC_DISP_SD_BL_PARAMETERS);
871 NVSD_PRINT_REG_ARRAY(DC_DISP_SD_BL_TF);
872 NVSD_PRINT_REG(DC_DISP_SD_BL_CONTROL);
873 NVSD_PRINT_REG(DC_DISP_SD_HW_K_VALUES);
874 NVSD_PRINT_REG(DC_DISP_SD_MAN_K_VALUES);
875
876 return res;
877}
878
879/* Sysfs initializer */
880int nvsd_create_sysfs(struct device *dev)
881{
882 int retval = 0;
883
884 nvsd_kobj = kobject_create_and_add("smartdimmer", &dev->kobj);
885
886 if (!nvsd_kobj)
887 return -ENOMEM;
888
889 retval = sysfs_create_group(nvsd_kobj, &nvsd_attr_group);
890
891 if (retval) {
892 kobject_put(nvsd_kobj);
893 dev_err(dev, "%s: failed to create attributes\n", __func__);
894 }
895
896 return retval;
897}
898
899/* Sysfs destructor */
900void __devexit nvsd_remove_sysfs(struct device *dev)
901{
902 if (nvsd_kobj) {
903 sysfs_remove_group(nvsd_kobj, &nvsd_attr_group);
904 kobject_put(nvsd_kobj);
905 }
906}
diff --git a/drivers/video/tegra/dc/nvsd.h b/drivers/video/tegra/dc/nvsd.h
new file mode 100644
index 00000000000..f7fc4a1ead6
--- /dev/null
+++ b/drivers/video/tegra/dc/nvsd.h
@@ -0,0 +1,25 @@
1/*
2 * drivers/video/tegra/dc/nvsd.h
3 *
4 * Copyright (c) 2010-2011, NVIDIA Corporation.
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16
17#ifndef __DRIVERS_VIDEO_TEGRA_DC_NVSD_H
18#define __DRIVERS_VIDEO_TEGRA_DC_NVSD_H
19
20void nvsd_init(struct tegra_dc *dc, struct tegra_dc_sd_settings *settings);
21bool nvsd_update_brightness(struct tegra_dc *dc);
22int nvsd_create_sysfs(struct device *dev);
23void __devexit nvsd_remove_sysfs(struct device *dev);
24
25#endif
diff --git a/drivers/video/tegra/dc/rgb.c b/drivers/video/tegra/dc/rgb.c
new file mode 100644
index 00000000000..2112643058f
--- /dev/null
+++ b/drivers/video/tegra/dc/rgb.c
@@ -0,0 +1,160 @@
1/*
2 * drivers/video/tegra/dc/rgb.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include <linux/kernel.h>
19
20#include <mach/dc.h>
21
22#include "dc_reg.h"
23#include "dc_priv.h"
24
25
26static const u32 tegra_dc_rgb_enable_partial_pintable[] = {
27 DC_COM_PIN_OUTPUT_ENABLE0, 0x00000000,
28 DC_COM_PIN_OUTPUT_ENABLE1, 0x00000000,
29 DC_COM_PIN_OUTPUT_ENABLE2, 0x00000000,
30 DC_COM_PIN_OUTPUT_ENABLE3, 0x00000000,
31 DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000,
32 DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000,
33 DC_COM_PIN_OUTPUT_DATA0, 0x00000000,
34 DC_COM_PIN_OUTPUT_DATA1, 0x00000000,
35 DC_COM_PIN_OUTPUT_DATA2, 0x00000000,
36 DC_COM_PIN_OUTPUT_DATA3, 0x00000000,
37};
38
39static const u32 tegra_dc_rgb_enable_pintable[] = {
40 DC_COM_PIN_OUTPUT_ENABLE0, 0x00000000,
41 DC_COM_PIN_OUTPUT_ENABLE1, 0x00000000,
42 DC_COM_PIN_OUTPUT_ENABLE2, 0x00000000,
43 DC_COM_PIN_OUTPUT_ENABLE3, 0x00000000,
44 DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000,
45 DC_COM_PIN_OUTPUT_POLARITY1, 0x01000000,
46 DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000,
47 DC_COM_PIN_OUTPUT_POLARITY3, 0x00000000,
48 DC_COM_PIN_OUTPUT_DATA0, 0x00000000,
49 DC_COM_PIN_OUTPUT_DATA1, 0x00000000,
50 DC_COM_PIN_OUTPUT_DATA2, 0x00000000,
51 DC_COM_PIN_OUTPUT_DATA3, 0x00000000,
52};
53
54static const u32 tegra_dc_rgb_enable_out_sel_pintable[] = {
55 DC_COM_PIN_OUTPUT_SELECT0, 0x00000000,
56 DC_COM_PIN_OUTPUT_SELECT1, 0x00000000,
57 DC_COM_PIN_OUTPUT_SELECT2, 0x00000000,
58#ifdef CONFIG_TEGRA_SILICON_PLATFORM
59 DC_COM_PIN_OUTPUT_SELECT3, 0x00000000,
60#else
61 /* The display panel sub-board used on FPGA platforms (panel 86)
62 is non-standard. It expects the Data Enable signal on the WR
63 pin instead of the DE pin. */
64 DC_COM_PIN_OUTPUT_SELECT3, 0x00200000,
65#endif
66 DC_COM_PIN_OUTPUT_SELECT4, 0x00210222,
67 DC_COM_PIN_OUTPUT_SELECT5, 0x00002200,
68 DC_COM_PIN_OUTPUT_SELECT6, 0x00020000,
69};
70
71static const u32 tegra_dc_rgb_disable_pintable[] = {
72 DC_COM_PIN_OUTPUT_ENABLE0, 0x55555555,
73 DC_COM_PIN_OUTPUT_ENABLE1, 0x55150005,
74 DC_COM_PIN_OUTPUT_ENABLE2, 0x55555555,
75 DC_COM_PIN_OUTPUT_ENABLE3, 0x55555555,
76 DC_COM_PIN_OUTPUT_POLARITY0, 0x00000000,
77 DC_COM_PIN_OUTPUT_POLARITY1, 0x00000000,
78 DC_COM_PIN_OUTPUT_POLARITY2, 0x00000000,
79 DC_COM_PIN_OUTPUT_POLARITY3, 0x00000000,
80 DC_COM_PIN_OUTPUT_DATA0, 0xaaaaaaaa,
81 DC_COM_PIN_OUTPUT_DATA1, 0xaaaaaaaa,
82 DC_COM_PIN_OUTPUT_DATA2, 0xaaaaaaaa,
83 DC_COM_PIN_OUTPUT_DATA3, 0xaaaaaaaa,
84 DC_COM_PIN_OUTPUT_SELECT0, 0x00000000,
85 DC_COM_PIN_OUTPUT_SELECT1, 0x00000000,
86 DC_COM_PIN_OUTPUT_SELECT2, 0x00000000,
87 DC_COM_PIN_OUTPUT_SELECT3, 0x00000000,
88 DC_COM_PIN_OUTPUT_SELECT4, 0x00000000,
89 DC_COM_PIN_OUTPUT_SELECT5, 0x00000000,
90 DC_COM_PIN_OUTPUT_SELECT6, 0x00000000,
91};
92
93void tegra_dc_rgb_enable(struct tegra_dc *dc)
94{
95 int i;
96 u32 out_sel_pintable[ARRAY_SIZE(tegra_dc_rgb_enable_out_sel_pintable)];
97
98 tegra_dc_writel(dc, PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
99 PW4_ENABLE | PM0_ENABLE | PM1_ENABLE,
100 DC_CMD_DISPLAY_POWER_CONTROL);
101
102 tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
103
104 if (dc->out->out_pins) {
105 tegra_dc_set_out_pin_polars(dc, dc->out->out_pins,
106 dc->out->n_out_pins);
107 tegra_dc_write_table(dc, tegra_dc_rgb_enable_partial_pintable);
108 } else {
109 tegra_dc_write_table(dc, tegra_dc_rgb_enable_pintable);
110 }
111
112 memcpy(out_sel_pintable, tegra_dc_rgb_enable_out_sel_pintable,
113 sizeof(tegra_dc_rgb_enable_out_sel_pintable));
114
115 if (dc->out && dc->out->out_sel_configs) {
116 u8 *out_sels = dc->out->out_sel_configs;
117 for (i = 0; i < dc->out->n_out_sel_configs; i++) {
118 switch (out_sels[i]) {
119 case TEGRA_PIN_OUT_CONFIG_SEL_LM1_M1:
120 out_sel_pintable[5*2+1] =
121 (out_sel_pintable[5*2+1] &
122 ~PIN5_LM1_LCD_M1_OUTPUT_MASK) |
123 PIN5_LM1_LCD_M1_OUTPUT_M1;
124 break;
125 case TEGRA_PIN_OUT_CONFIG_SEL_LM1_LD21:
126 out_sel_pintable[5*2+1] =
127 (out_sel_pintable[5*2+1] &
128 ~PIN5_LM1_LCD_M1_OUTPUT_MASK) |
129 PIN5_LM1_LCD_M1_OUTPUT_LD21;
130 break;
131 case TEGRA_PIN_OUT_CONFIG_SEL_LM1_PM1:
132 out_sel_pintable[5*2+1] =
133 (out_sel_pintable[5*2+1] &
134 ~PIN5_LM1_LCD_M1_OUTPUT_MASK) |
135 PIN5_LM1_LCD_M1_OUTPUT_PM1;
136 break;
137 default:
138 dev_err(&dc->ndev->dev,
139 "Invalid pin config[%d]: %d\n",
140 i, out_sels[i]);
141 break;
142 }
143 }
144 }
145
146 tegra_dc_write_table(dc, out_sel_pintable);
147}
148
149void tegra_dc_rgb_disable(struct tegra_dc *dc)
150{
151 tegra_dc_writel(dc, 0x00000000, DC_CMD_DISPLAY_POWER_CONTROL);
152
153 tegra_dc_write_table(dc, tegra_dc_rgb_disable_pintable);
154}
155
156struct tegra_dc_out_ops tegra_dc_rgb_ops = {
157 .enable = tegra_dc_rgb_enable,
158 .disable = tegra_dc_rgb_disable,
159};
160
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
new file mode 100644
index 00000000000..7bc3ab06c47
--- /dev/null
+++ b/drivers/video/tegra/fb.c
@@ -0,0 +1,625 @@
1/*
2 * drivers/video/tegra/fb.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 * Colin Cross <ccross@android.com>
7 * Travis Geiselbrecht <travis@palm.com>
8 *
9 * Copyright (C) 2010-2011 NVIDIA Corporation
10 *
11 * This software is licensed under the terms of the GNU General Public
12 * License version 2, as published by the Free Software Foundation, and
13 * may be copied, distributed, and modified under those terms.
14 *
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
22#include <linux/fb.h>
23#include <linux/module.h>
24#include <linux/kernel.h>
25#include <linux/errno.h>
26#include <linux/string.h>
27#include <linux/mm.h>
28#include <linux/uaccess.h>
29#include <linux/slab.h>
30#include <linux/file.h>
31#include <linux/workqueue.h>
32
33#include <asm/atomic.h>
34
35#include <video/tegrafb.h>
36
37#include <mach/dc.h>
38#include <mach/fb.h>
39#include <linux/nvhost.h>
40#include <mach/nvmap.h>
41
42#include "host/dev.h"
43#include "nvmap/nvmap.h"
44#include "dc/dc_priv.h"
45
46/* Pad pitch to 16-byte boundary. */
47#define TEGRA_LINEAR_PITCH_ALIGNMENT 16
48
49struct tegra_fb_info {
50 struct tegra_dc_win *win;
51 struct nvhost_device *ndev;
52 struct fb_info *info;
53 bool valid;
54
55 struct resource *fb_mem;
56
57 int xres;
58 int yres;
59};
60
61/* palette array used by the fbcon */
62static u32 pseudo_palette[16];
63
64static int tegra_fb_check_var(struct fb_var_screeninfo *var,
65 struct fb_info *info)
66{
67 if ((var->yres * var->xres * var->bits_per_pixel / 8 * 2) >
68 info->screen_size)
69 return -EINVAL;
70
71 /* double yres_virtual to allow double buffering through pan_display */
72 var->yres_virtual = var->yres * 2;
73
74 return 0;
75}
76
77static int tegra_fb_set_par(struct fb_info *info)
78{
79 struct tegra_fb_info *tegra_fb = info->par;
80 struct fb_var_screeninfo *var = &info->var;
81
82 if (var->bits_per_pixel) {
83 /* we only support RGB ordering for now */
84 switch (var->bits_per_pixel) {
85 case 32:
86 var->red.offset = 0;
87 var->red.length = 8;
88 var->green.offset = 8;
89 var->green.length = 8;
90 var->blue.offset = 16;
91 var->blue.length = 8;
92 var->transp.offset = 24;
93 var->transp.length = 8;
94 tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
95 break;
96 case 16:
97 var->red.offset = 11;
98 var->red.length = 5;
99 var->green.offset = 5;
100 var->green.length = 6;
101 var->blue.offset = 0;
102 var->blue.length = 5;
103 tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
104 break;
105
106 default:
107 return -EINVAL;
108 }
109 info->fix.line_length = var->xres * var->bits_per_pixel / 8;
110 /* Pad the stride to 16-byte boundary. */
111 info->fix.line_length = round_up(info->fix.line_length,
112 TEGRA_LINEAR_PITCH_ALIGNMENT);
113 tegra_fb->win->stride = info->fix.line_length;
114 tegra_fb->win->stride_uv = 0;
115 tegra_fb->win->phys_addr_u = 0;
116 tegra_fb->win->phys_addr_v = 0;
117 }
118
119 if (var->pixclock) {
120 bool stereo;
121 struct fb_videomode m;
122
123 fb_var_to_videomode(&m, var);
124
125 info->mode = (struct fb_videomode *)
126 fb_find_nearest_mode(&m, &info->modelist);
127 if (!info->mode) {
128 dev_warn(&tegra_fb->ndev->dev, "can't match video mode\n");
129 return -EINVAL;
130 }
131
132 /*
133 * only enable stereo if the mode supports it and
134 * client requests it
135 */
136 stereo = !!(var->vmode & info->mode->vmode &
137#ifndef CONFIG_TEGRA_HDMI_74MHZ_LIMIT
138 FB_VMODE_STEREO_FRAME_PACK);
139#else
140 FB_VMODE_STEREO_LEFT_RIGHT);
141#endif
142
143 tegra_dc_set_fb_mode(tegra_fb->win->dc, info->mode, stereo);
144
145 tegra_fb->win->w.full = dfixed_const(info->mode->xres);
146 tegra_fb->win->h.full = dfixed_const(info->mode->yres);
147 tegra_fb->win->out_w = info->mode->xres;
148 tegra_fb->win->out_h = info->mode->yres;
149 }
150 return 0;
151}
152
153static int tegra_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
154 unsigned blue, unsigned transp, struct fb_info *info)
155{
156 struct fb_var_screeninfo *var = &info->var;
157
158 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
159 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
160 u32 v;
161
162 if (regno >= 16)
163 return -EINVAL;
164
165 red = (red >> (16 - info->var.red.length));
166 green = (green >> (16 - info->var.green.length));
167 blue = (blue >> (16 - info->var.blue.length));
168
169 v = (red << var->red.offset) |
170 (green << var->green.offset) |
171 (blue << var->blue.offset);
172
173 ((u32 *)info->pseudo_palette)[regno] = v;
174 }
175
176 return 0;
177}
178
179
180static int tegra_fb_setcmap(struct fb_cmap *cmap, struct fb_info *info)
181{
182 struct tegra_fb_info *tegra_fb = info->par;
183 struct tegra_dc *dc = tegra_fb->win->dc;
184 int i;
185 u16 *red = cmap->red;
186 u16 *green = cmap->green;
187 u16 *blue = cmap->blue;
188 int start = cmap->start;
189
190 if (((unsigned)start > 255) || ((start + cmap->len) > 256))
191 return -EINVAL;
192
193 if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
194 info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
195 /*
196 * For now we are considering color schemes with
197 * cmap->len <=16 as special case of basic color
198 * scheme to support fbconsole.But for DirectColor
199 * visuals(like the one we actually have, that include
200 * a HW LUT),the way it's intended to work is that the
201 * actual LUT HW is programmed to the intended values,
202 * even for small color maps like those with 16 or fewer
203 * entries. The pseudo_palette is then programmed to the
204 * identity transform.
205 */
206 if (cmap->len <= 16) {
207 /* Low-color schemes like fbconsole*/
208 u16 *transp = cmap->transp;
209 u_int vtransp = 0xffff;
210
211 for (i = 0; i < cmap->len; i++) {
212 if (transp)
213 vtransp = *transp++;
214 if (tegra_fb_setcolreg(start++, *red++,
215 *green++, *blue++,
216 vtransp, info))
217 return -EINVAL;
218 }
219 } else {
220 /* High-color schemes*/
221 for (i = 0; i < cmap->len; i++) {
222 dc->fb_lut.r[start+i] = *red++ >> 8;
223 dc->fb_lut.g[start+i] = *green++ >> 8;
224 dc->fb_lut.b[start+i] = *blue++ >> 8;
225 }
226 tegra_dc_update_lut(dc, -1, -1);
227 }
228 }
229 return 0;
230}
231
232#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
233static void tegra_fb_flip_win(struct tegra_fb_info *tegra_fb)
234{
235 struct tegra_dc_win *win = tegra_fb->win;
236 struct fb_info *info = tegra_fb->info;
237
238 win->x.full = dfixed_const(0);
239 win->y.full = dfixed_const(0);
240 win->w.full = dfixed_const(tegra_fb->xres);
241 win->h.full = dfixed_const(tegra_fb->yres);
242
243 /* TODO: set to output res dc */
244 win->out_x = 0;
245 win->out_y = 0;
246 win->out_w = tegra_fb->xres;
247 win->out_h = tegra_fb->yres;
248 win->z = 0;
249 win->phys_addr = info->fix.smem_start +
250 (info->var.yoffset * info->fix.line_length) +
251 (info->var.xoffset * (info->var.bits_per_pixel / 8));
252 win->virt_addr = info->screen_base;
253
254 win->phys_addr_u = 0;
255 win->phys_addr_v = 0;
256 win->stride = info->fix.line_length;
257 win->stride_uv = 0;
258
259 switch (info->var.bits_per_pixel) {
260 default:
261 WARN_ON(1);
262 /* fall through */
263 case 32:
264 tegra_fb->win->fmt = TEGRA_WIN_FMT_R8G8B8A8;
265 break;
266 case 16:
267 tegra_fb->win->fmt = TEGRA_WIN_FMT_B5G6R5;
268 break;
269 }
270 win->flags = TEGRA_WIN_FLAG_ENABLED;
271
272 tegra_dc_update_windows(&tegra_fb->win, 1);
273 tegra_dc_sync_windows(&tegra_fb->win, 1);
274}
275#endif
276
277static int tegra_fb_blank(int blank, struct fb_info *info)
278{
279 struct tegra_fb_info *tegra_fb = info->par;
280
281 switch (blank) {
282 case FB_BLANK_UNBLANK:
283 dev_dbg(&tegra_fb->ndev->dev, "unblank\n");
284 tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
285 tegra_dc_enable(tegra_fb->win->dc);
286#if defined(CONFIG_FRAMEBUFFER_CONSOLE)
287 /*
288 * TODO:
289 * This is a work around to provide an unblanking flip
290 * to dc driver, required to display fb-console after
291 * a blank event,and needs to be replaced by a proper
292 * unblanking mechanism
293 */
294 tegra_fb_flip_win(tegra_fb);
295#endif
296 return 0;
297
298 case FB_BLANK_NORMAL:
299 dev_dbg(&tegra_fb->ndev->dev, "blank - normal\n");
300 tegra_dc_blank(tegra_fb->win->dc);
301 return 0;
302
303 case FB_BLANK_VSYNC_SUSPEND:
304 case FB_BLANK_HSYNC_SUSPEND:
305 case FB_BLANK_POWERDOWN:
306 dev_dbg(&tegra_fb->ndev->dev, "blank - powerdown\n");
307 tegra_dc_disable(tegra_fb->win->dc);
308 return 0;
309
310 default:
311 return -ENOTTY;
312 }
313}
314
315static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
316 struct fb_info *info)
317{
318 struct tegra_fb_info *tegra_fb = info->par;
319 char __iomem *flush_start;
320 char __iomem *flush_end;
321 u32 addr;
322
323 if (!tegra_fb->win->cur_handle) {
324 flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
325 flush_end = flush_start + (var->yres * info->fix.line_length);
326
327 info->var.xoffset = var->xoffset;
328 info->var.yoffset = var->yoffset;
329
330 addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
331 (var->xoffset * (var->bits_per_pixel/8));
332
333 tegra_fb->win->phys_addr = addr;
334 /* TODO: update virt_addr */
335
336 tegra_dc_update_windows(&tegra_fb->win, 1);
337 tegra_dc_sync_windows(&tegra_fb->win, 1);
338 }
339
340 return 0;
341}
342
343static void tegra_fb_fillrect(struct fb_info *info,
344 const struct fb_fillrect *rect)
345{
346 cfb_fillrect(info, rect);
347}
348
349static void tegra_fb_copyarea(struct fb_info *info,
350 const struct fb_copyarea *region)
351{
352 cfb_copyarea(info, region);
353}
354
355static void tegra_fb_imageblit(struct fb_info *info,
356 const struct fb_image *image)
357{
358 cfb_imageblit(info, image);
359}
360
361static int tegra_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
362{
363 struct tegra_fb_modedb modedb;
364 struct fb_modelist *modelist;
365 int i;
366
367 switch (cmd) {
368 case FBIO_TEGRA_GET_MODEDB:
369 if (copy_from_user(&modedb, (void __user *)arg, sizeof(modedb)))
370 return -EFAULT;
371
372 i = 0;
373 list_for_each_entry(modelist, &info->modelist, list) {
374 struct fb_var_screeninfo var;
375
376 if (i >= modedb.modedb_len)
377 break;
378
379 /* fb_videomode_to_var doesn't fill out all the members
380 of fb_var_screeninfo */
381 memset(&var, 0x0, sizeof(var));
382
383 fb_videomode_to_var(&var, &modelist->mode);
384
385 if (copy_to_user((void __user *)&modedb.modedb[i],
386 &var, sizeof(var)))
387 return -EFAULT;
388 i++;
389
390 if (var.vmode & FB_VMODE_STEREO_MASK) {
391 if (i >= modedb.modedb_len)
392 break;
393 var.vmode &= ~FB_VMODE_STEREO_MASK;
394 if (copy_to_user(
395 (void __user *)&modedb.modedb[i],
396 &var, sizeof(var)))
397 return -EFAULT;
398 i++;
399 }
400 }
401 modedb.modedb_len = i;
402
403 if (copy_to_user((void __user *)arg, &modedb, sizeof(modedb)))
404 return -EFAULT;
405 break;
406
407 default:
408 return -ENOTTY;
409 }
410
411 return 0;
412}
413
414static struct fb_ops tegra_fb_ops = {
415 .owner = THIS_MODULE,
416 .fb_check_var = tegra_fb_check_var,
417 .fb_set_par = tegra_fb_set_par,
418 .fb_setcmap = tegra_fb_setcmap,
419 .fb_blank = tegra_fb_blank,
420 .fb_pan_display = tegra_fb_pan_display,
421 .fb_fillrect = tegra_fb_fillrect,
422 .fb_copyarea = tegra_fb_copyarea,
423 .fb_imageblit = tegra_fb_imageblit,
424 .fb_ioctl = tegra_fb_ioctl,
425};
426
427void tegra_fb_update_monspecs(struct tegra_fb_info *fb_info,
428 struct fb_monspecs *specs,
429 bool (*mode_filter)(const struct tegra_dc *dc,
430 struct fb_videomode *mode))
431{
432 struct fb_event event;
433 int i;
434
435 mutex_lock(&fb_info->info->lock);
436 fb_destroy_modedb(fb_info->info->monspecs.modedb);
437
438 fb_destroy_modelist(&fb_info->info->modelist);
439
440 if (specs == NULL) {
441 struct tegra_dc_mode mode;
442 memset(&fb_info->info->monspecs, 0x0,
443 sizeof(fb_info->info->monspecs));
444 memset(&mode, 0x0, sizeof(mode));
445
446 /*
447 * reset video mode properties to prevent garbage being displayed on 'mode' device.
448 */
449 fb_info->info->mode = (struct fb_videomode*) NULL;
450
451 tegra_dc_set_mode(fb_info->win->dc, &mode);
452 mutex_unlock(&fb_info->info->lock);
453 return;
454 }
455
456 memcpy(&fb_info->info->monspecs, specs,
457 sizeof(fb_info->info->monspecs));
458
459 for (i = 0; i < specs->modedb_len; i++) {
460 if (mode_filter) {
461 if (mode_filter(fb_info->win->dc, &specs->modedb[i]))
462 fb_add_videomode(&specs->modedb[i],
463 &fb_info->info->modelist);
464 } else {
465 fb_add_videomode(&specs->modedb[i],
466 &fb_info->info->modelist);
467 }
468 }
469
470 event.info = fb_info->info;
471 fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
472 mutex_unlock(&fb_info->info->lock);
473}
474
475struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
476 struct tegra_dc *dc,
477 struct tegra_fb_data *fb_data,
478 struct resource *fb_mem)
479{
480 struct tegra_dc_win *win;
481 struct fb_info *info;
482 struct tegra_fb_info *tegra_fb;
483 void __iomem *fb_base = NULL;
484 unsigned long fb_size = 0;
485 unsigned long fb_phys = 0;
486 int ret = 0;
487
488 win = tegra_dc_get_window(dc, fb_data->win);
489 if (!win) {
490 dev_err(&ndev->dev, "dc does not have a window at index %d\n",
491 fb_data->win);
492 return ERR_PTR(-ENOENT);
493 }
494
495 info = framebuffer_alloc(sizeof(struct tegra_fb_info), &ndev->dev);
496 if (!info) {
497 ret = -ENOMEM;
498 goto err;
499 }
500
501 tegra_fb = info->par;
502 tegra_fb->win = win;
503 tegra_fb->ndev = ndev;
504 tegra_fb->fb_mem = fb_mem;
505 tegra_fb->xres = fb_data->xres;
506 tegra_fb->yres = fb_data->yres;
507
508 if (fb_mem) {
509 fb_size = resource_size(fb_mem);
510 fb_phys = fb_mem->start;
511 fb_base = ioremap_nocache(fb_phys, fb_size);
512 if (!fb_base) {
513 dev_err(&ndev->dev, "fb can't be mapped\n");
514 ret = -EBUSY;
515 goto err_free;
516 }
517 tegra_fb->valid = true;
518 }
519
520 info->fbops = &tegra_fb_ops;
521 info->pseudo_palette = pseudo_palette;
522 info->screen_base = fb_base;
523 info->screen_size = fb_size;
524
525 strlcpy(info->fix.id, "tegra_fb", sizeof(info->fix.id));
526 info->fix.type = FB_TYPE_PACKED_PIXELS;
527 info->fix.visual = FB_VISUAL_TRUECOLOR;
528 info->fix.xpanstep = 1;
529 info->fix.ypanstep = 1;
530 info->fix.accel = FB_ACCEL_NONE;
531 info->fix.smem_start = fb_phys;
532 info->fix.smem_len = fb_size;
533 info->fix.line_length = fb_data->xres * fb_data->bits_per_pixel / 8;
534 /* Pad the stride to 16-byte boundary. */
535 info->fix.line_length = round_up(info->fix.line_length,
536 TEGRA_LINEAR_PITCH_ALIGNMENT);
537
538 info->var.xres = fb_data->xres;
539 info->var.yres = fb_data->yres;
540 info->var.xres_virtual = fb_data->xres;
541 info->var.yres_virtual = fb_data->yres * 2;
542 info->var.bits_per_pixel = fb_data->bits_per_pixel;
543 info->var.activate = FB_ACTIVATE_VBL;
544 info->var.height = tegra_dc_get_out_height(dc);
545 info->var.width = tegra_dc_get_out_width(dc);
546 info->var.pixclock = 0;
547 info->var.left_margin = 0;
548 info->var.right_margin = 0;
549 info->var.upper_margin = 0;
550 info->var.lower_margin = 0;
551 info->var.hsync_len = 0;
552 info->var.vsync_len = 0;
553 info->var.vmode = FB_VMODE_NONINTERLACED;
554
555 win->x.full = dfixed_const(0);
556 win->y.full = dfixed_const(0);
557 win->w.full = dfixed_const(fb_data->xres);
558 win->h.full = dfixed_const(fb_data->yres);
559 /* TODO: set to output res dc */
560 win->out_x = 0;
561 win->out_y = 0;
562 win->out_w = fb_data->xres;
563 win->out_h = fb_data->yres;
564 win->z = 0;
565 win->phys_addr = fb_phys;
566 win->virt_addr = fb_base;
567 win->phys_addr_u = 0;
568 win->phys_addr_v = 0;
569 win->stride = info->fix.line_length;
570 win->stride_uv = 0;
571 win->flags = TEGRA_WIN_FLAG_ENABLED;
572
573 if (fb_mem)
574 tegra_fb_set_par(info);
575
576 if (register_framebuffer(info)) {
577 dev_err(&ndev->dev, "failed to register framebuffer\n");
578 ret = -ENODEV;
579 goto err_iounmap_fb;
580 }
581
582 tegra_fb->info = info;
583
584 dev_info(&ndev->dev, "probed\n");
585
586 if (fb_data->flags & TEGRA_FB_FLIP_ON_PROBE) {
587 tegra_dc_update_windows(&tegra_fb->win, 1);
588 tegra_dc_sync_windows(&tegra_fb->win, 1);
589 }
590
591 if (dc->mode.pclk > 1000) {
592 struct tegra_dc_mode *mode = &dc->mode;
593
594 if (dc->out->flags & TEGRA_DC_OUT_ONE_SHOT_MODE)
595 info->var.pixclock = KHZ2PICOS(mode->rated_pclk / 1000);
596 else
597 info->var.pixclock = KHZ2PICOS(mode->pclk / 1000);
598 info->var.left_margin = mode->h_back_porch;
599 info->var.right_margin = mode->h_front_porch;
600 info->var.upper_margin = mode->v_back_porch;
601 info->var.lower_margin = mode->v_front_porch;
602 info->var.hsync_len = mode->h_sync_width;
603 info->var.vsync_len = mode->v_sync_width;
604 }
605
606 return tegra_fb;
607
608err_iounmap_fb:
609 if (fb_base)
610 iounmap(fb_base);
611err_free:
612 framebuffer_release(info);
613err:
614 return ERR_PTR(ret);
615}
616
617void tegra_fb_unregister(struct tegra_fb_info *fb_info)
618{
619 struct fb_info *info = fb_info->info;
620
621 unregister_framebuffer(info);
622
623 iounmap(info->screen_base);
624 framebuffer_release(info);
625}
diff --git a/drivers/video/tegra/host/Makefile b/drivers/video/tegra/host/Makefile
new file mode 100644
index 00000000000..0180885af4d
--- /dev/null
+++ b/drivers/video/tegra/host/Makefile
@@ -0,0 +1,23 @@
1GCOV_PROFILE := y
2nvhost-objs = \
3 nvhost_acm.o \
4 nvhost_syncpt.o \
5 nvhost_cdma.o \
6 nvhost_intr.o \
7 nvhost_channel.o \
8 nvhost_job.o \
9 bus.o \
10 dev.o \
11 debug.o \
12 bus_client.o
13
14obj-$(CONFIG_TEGRA_GRHOST) += mpe/
15obj-$(CONFIG_TEGRA_GRHOST) += gr3d/
16obj-$(CONFIG_TEGRA_GRHOST) += host1x/
17obj-$(CONFIG_TEGRA_GRHOST) += t20/
18obj-$(CONFIG_TEGRA_GRHOST) += t30/
19obj-$(CONFIG_TEGRA_GRHOST) += dsi/
20obj-$(CONFIG_TEGRA_GRHOST) += gr2d/
21obj-$(CONFIG_TEGRA_GRHOST) += isp/
22obj-$(CONFIG_TEGRA_GRHOST) += vi/
23obj-$(CONFIG_TEGRA_GRHOST) += nvhost.o
diff --git a/drivers/video/tegra/host/bus.c b/drivers/video/tegra/host/bus.c
new file mode 100644
index 00000000000..774aac7bd43
--- /dev/null
+++ b/drivers/video/tegra/host/bus.c
@@ -0,0 +1,569 @@
1/*
2 * drivers/video/tegra/host/bus.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@google.com>
6 *
7 * Copyright (C) 2010-2012 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/pm_runtime.h>
21#include <linux/nvhost.h>
22
23#include "dev.h"
24
25struct nvhost_master *nvhost;
26
27struct resource *nvhost_get_resource(struct nvhost_device *dev,
28 unsigned int type, unsigned int num)
29{
30 int i;
31
32 for (i = 0; i < dev->num_resources; i++) {
33 struct resource *r = &dev->resource[i];
34
35 if (type == resource_type(r) && num-- == 0)
36 return r;
37 }
38 return NULL;
39}
40EXPORT_SYMBOL_GPL(nvhost_get_resource);
41
42int nvhost_get_irq(struct nvhost_device *dev, unsigned int num)
43{
44 struct resource *r = nvhost_get_resource(dev, IORESOURCE_IRQ, num);
45
46 return r ? r->start : -ENXIO;
47}
48EXPORT_SYMBOL_GPL(nvhost_get_irq);
49
50struct resource *nvhost_get_resource_byname(struct nvhost_device *dev,
51 unsigned int type,
52 const char *name)
53{
54 int i;
55
56 for (i = 0; i < dev->num_resources; i++) {
57 struct resource *r = &dev->resource[i];
58
59 if (type == resource_type(r) && !strcmp(r->name, name))
60 return r;
61 }
62 return NULL;
63}
64EXPORT_SYMBOL_GPL(nvhost_get_resource_byname);
65
66int nvhost_get_irq_byname(struct nvhost_device *dev, const char *name)
67{
68 struct resource *r = nvhost_get_resource_byname(dev, IORESOURCE_IRQ,
69 name);
70
71 return r ? r->start : -ENXIO;
72}
73EXPORT_SYMBOL_GPL(nvhost_get_irq_byname);
74
75static int nvhost_drv_probe(struct device *_dev)
76{
77 struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
78 struct nvhost_device *dev = to_nvhost_device(_dev);
79
80 return drv->probe(dev);
81}
82
83static int nvhost_drv_remove(struct device *_dev)
84{
85 struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
86 struct nvhost_device *dev = to_nvhost_device(_dev);
87
88 return drv->remove(dev);
89}
90
91static void nvhost_drv_shutdown(struct device *_dev)
92{
93 struct nvhost_driver *drv = to_nvhost_driver(_dev->driver);
94 struct nvhost_device *dev = to_nvhost_device(_dev);
95
96 drv->shutdown(dev);
97}
98
99int nvhost_driver_register(struct nvhost_driver *drv)
100{
101 drv->driver.bus = &nvhost_bus_type;
102 if (drv->probe)
103 drv->driver.probe = nvhost_drv_probe;
104 if (drv->remove)
105 drv->driver.remove = nvhost_drv_remove;
106 if (drv->shutdown)
107 drv->driver.shutdown = nvhost_drv_shutdown;
108
109 return driver_register(&drv->driver);
110}
111EXPORT_SYMBOL(nvhost_driver_register);
112
113void nvhost_driver_unregister(struct nvhost_driver *drv)
114{
115 driver_unregister(&drv->driver);
116}
117EXPORT_SYMBOL_GPL(nvhost_driver_unregister);
118
119int nvhost_device_register(struct nvhost_device *dev)
120{
121 int i, ret = 0;
122
123 if (!dev)
124 return -EINVAL;
125
126 device_initialize(&dev->dev);
127
128 /* If the dev does not have a parent, assign host1x as parent */
129 if (!dev->dev.parent && nvhost && nvhost->dev != dev)
130 dev->dev.parent = &nvhost->dev->dev;
131
132 dev->dev.bus = &nvhost_bus_type;
133
134 if (dev->id != -1)
135 dev_set_name(&dev->dev, "%s.%d", dev->name, dev->id);
136 else
137 dev_set_name(&dev->dev, "%s", dev->name);
138
139 for (i = 0; i < dev->num_resources; i++) {
140 struct resource *p, *r = &dev->resource[i];
141
142 if (r->name == NULL)
143 r->name = dev_name(&dev->dev);
144
145 p = r->parent;
146 if (!p) {
147 if (resource_type(r) == IORESOURCE_MEM)
148 p = &iomem_resource;
149 else if (resource_type(r) == IORESOURCE_IO)
150 p = &ioport_resource;
151 }
152
153 if (p && insert_resource(p, r)) {
154 pr_err("%s: failed to claim resource %d\n",
155 dev_name(&dev->dev), i);
156 ret = -EBUSY;
157 goto failed;
158 }
159 }
160
161 ret = device_add(&dev->dev);
162 if (ret == 0)
163 return ret;
164
165failed:
166 while (--i >= 0) {
167 struct resource *r = &dev->resource[i];
168 unsigned long type = resource_type(r);
169
170 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
171 release_resource(r);
172 }
173
174 return ret;
175}
176EXPORT_SYMBOL_GPL(nvhost_device_register);
177
178void nvhost_device_unregister(struct nvhost_device *dev)
179{
180 int i;
181 if (dev) {
182 device_del(&dev->dev);
183
184 for (i = 0; i < dev->num_resources; i++) {
185 struct resource *r = &dev->resource[i];
186 unsigned long type = resource_type(r);
187
188 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
189 release_resource(r);
190 }
191
192 put_device(&dev->dev);
193 }
194}
195EXPORT_SYMBOL_GPL(nvhost_device_unregister);
196
197static int nvhost_bus_match(struct device *_dev, struct device_driver *drv)
198{
199 struct nvhost_device *dev = to_nvhost_device(_dev);
200
201 return !strncmp(dev->name, drv->name, strlen(drv->name));
202}
203
204#ifdef CONFIG_PM_SLEEP
205
206static int nvhost_legacy_suspend(struct device *dev, pm_message_t mesg)
207{
208 struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
209 struct nvhost_device *pdev = to_nvhost_device(dev);
210 int ret = 0;
211
212 if (dev->driver && pdrv->suspend)
213 ret = pdrv->suspend(pdev, mesg);
214
215 return ret;
216}
217
218static int nvhost_legacy_resume(struct device *dev)
219{
220 struct nvhost_driver *pdrv = to_nvhost_driver(dev->driver);
221 struct nvhost_device *pdev = to_nvhost_device(dev);
222 int ret = 0;
223
224 if (dev->driver && pdrv->resume)
225 ret = pdrv->resume(pdev);
226
227 return ret;
228}
229
230static int nvhost_pm_prepare(struct device *dev)
231{
232 struct device_driver *drv = dev->driver;
233 int ret = 0;
234
235 if (drv && drv->pm && drv->pm->prepare)
236 ret = drv->pm->prepare(dev);
237
238 return ret;
239}
240
241static void nvhost_pm_complete(struct device *dev)
242{
243 struct device_driver *drv = dev->driver;
244
245 if (drv && drv->pm && drv->pm->complete)
246 drv->pm->complete(dev);
247}
248
249#else /* !CONFIG_PM_SLEEP */
250
251#define nvhost_pm_prepare NULL
252#define nvhost_pm_complete NULL
253
254#endif /* !CONFIG_PM_SLEEP */
255
256#ifdef CONFIG_SUSPEND
257
258int __weak nvhost_pm_suspend(struct device *dev)
259{
260 struct device_driver *drv = dev->driver;
261 int ret = 0;
262
263 if (!drv)
264 return 0;
265
266 if (drv->pm) {
267 if (drv->pm->suspend)
268 ret = drv->pm->suspend(dev);
269 } else {
270 ret = nvhost_legacy_suspend(dev, PMSG_SUSPEND);
271 }
272
273 return ret;
274}
275
276int __weak nvhost_pm_suspend_noirq(struct device *dev)
277{
278 struct device_driver *drv = dev->driver;
279 int ret = 0;
280
281 if (!drv)
282 return 0;
283
284 if (drv->pm) {
285 if (drv->pm->suspend_noirq)
286 ret = drv->pm->suspend_noirq(dev);
287 }
288
289 return ret;
290}
291
292int __weak nvhost_pm_resume(struct device *dev)
293{
294 struct device_driver *drv = dev->driver;
295 int ret = 0;
296
297 if (!drv)
298 return 0;
299
300 if (drv->pm) {
301 if (drv->pm->resume)
302 ret = drv->pm->resume(dev);
303 } else {
304 ret = nvhost_legacy_resume(dev);
305 }
306
307 return ret;
308}
309
310int __weak nvhost_pm_resume_noirq(struct device *dev)
311{
312 struct device_driver *drv = dev->driver;
313 int ret = 0;
314
315 if (!drv)
316 return 0;
317
318 if (drv->pm) {
319 if (drv->pm->resume_noirq)
320 ret = drv->pm->resume_noirq(dev);
321 }
322
323 return ret;
324}
325
326#else /* !CONFIG_SUSPEND */
327
328#define nvhost_pm_suspend NULL
329#define nvhost_pm_resume NULL
330#define nvhost_pm_suspend_noirq NULL
331#define nvhost_pm_resume_noirq NULL
332
333#endif /* !CONFIG_SUSPEND */
334
335#ifdef CONFIG_HIBERNATION
336
337static int nvhost_pm_freeze(struct device *dev)
338{
339 struct device_driver *drv = dev->driver;
340 int ret = 0;
341
342 if (!drv)
343 return 0;
344
345 if (drv->pm) {
346 if (drv->pm->freeze)
347 ret = drv->pm->freeze(dev);
348 } else {
349 ret = nvhost_legacy_suspend(dev, PMSG_FREEZE);
350 }
351
352 return ret;
353}
354
355static int nvhost_pm_freeze_noirq(struct device *dev)
356{
357 struct device_driver *drv = dev->driver;
358 int ret = 0;
359
360 if (!drv)
361 return 0;
362
363 if (drv->pm) {
364 if (drv->pm->freeze_noirq)
365 ret = drv->pm->freeze_noirq(dev);
366 }
367
368 return ret;
369}
370
371static int nvhost_pm_thaw(struct device *dev)
372{
373 struct device_driver *drv = dev->driver;
374 int ret = 0;
375
376 if (!drv)
377 return 0;
378
379 if (drv->pm) {
380 if (drv->pm->thaw)
381 ret = drv->pm->thaw(dev);
382 } else {
383 ret = nvhost_legacy_resume(dev);
384 }
385
386 return ret;
387}
388
389static int nvhost_pm_thaw_noirq(struct device *dev)
390{
391 struct device_driver *drv = dev->driver;
392 int ret = 0;
393
394 if (!drv)
395 return 0;
396
397 if (drv->pm) {
398 if (drv->pm->thaw_noirq)
399 ret = drv->pm->thaw_noirq(dev);
400 }
401
402 return ret;
403}
404
405static int nvhost_pm_poweroff(struct device *dev)
406{
407 struct device_driver *drv = dev->driver;
408 int ret = 0;
409
410 if (!drv)
411 return 0;
412
413 if (drv->pm) {
414 if (drv->pm->poweroff)
415 ret = drv->pm->poweroff(dev);
416 } else {
417 ret = nvhost_legacy_suspend(dev, PMSG_HIBERNATE);
418 }
419
420 return ret;
421}
422
423static int nvhost_pm_poweroff_noirq(struct device *dev)
424{
425 struct device_driver *drv = dev->driver;
426 int ret = 0;
427
428 if (!drv)
429 return 0;
430
431 if (drv->pm) {
432 if (drv->pm->poweroff_noirq)
433 ret = drv->pm->poweroff_noirq(dev);
434 }
435
436 return ret;
437}
438
439static int nvhost_pm_restore(struct device *dev)
440{
441 struct device_driver *drv = dev->driver;
442 int ret = 0;
443
444 if (!drv)
445 return 0;
446
447 if (drv->pm) {
448 if (drv->pm->restore)
449 ret = drv->pm->restore(dev);
450 } else {
451 ret = nvhost_legacy_resume(dev);
452 }
453
454 return ret;
455}
456
457static int nvhost_pm_restore_noirq(struct device *dev)
458{
459 struct device_driver *drv = dev->driver;
460 int ret = 0;
461
462 if (!drv)
463 return 0;
464
465 if (drv->pm) {
466 if (drv->pm->restore_noirq)
467 ret = drv->pm->restore_noirq(dev);
468 }
469
470 return ret;
471}
472
473#else /* !CONFIG_HIBERNATION */
474
475#define nvhost_pm_freeze NULL
476#define nvhost_pm_thaw NULL
477#define nvhost_pm_poweroff NULL
478#define nvhost_pm_restore NULL
479#define nvhost_pm_freeze_noirq NULL
480#define nvhost_pm_thaw_noirq NULL
481#define nvhost_pm_poweroff_noirq NULL
482#define nvhost_pm_restore_noirq NULL
483
484#endif /* !CONFIG_HIBERNATION */
485
486#ifdef CONFIG_PM_RUNTIME
487
488int __weak nvhost_pm_runtime_suspend(struct device *dev)
489{
490 return pm_generic_runtime_suspend(dev);
491};
492
493int __weak nvhost_pm_runtime_resume(struct device *dev)
494{
495 return pm_generic_runtime_resume(dev);
496};
497
498int __weak nvhost_pm_runtime_idle(struct device *dev)
499{
500 return pm_generic_runtime_idle(dev);
501};
502
503#else /* !CONFIG_PM_RUNTIME */
504
505#define nvhost_pm_runtime_suspend NULL
506#define nvhost_pm_runtime_resume NULL
507#define nvhost_pm_runtime_idle NULL
508
509#endif /* !CONFIG_PM_RUNTIME */
510
511static const struct dev_pm_ops nvhost_dev_pm_ops = {
512 .prepare = nvhost_pm_prepare,
513 .complete = nvhost_pm_complete,
514 .suspend = nvhost_pm_suspend,
515 .resume = nvhost_pm_resume,
516 .freeze = nvhost_pm_freeze,
517 .thaw = nvhost_pm_thaw,
518 .poweroff = nvhost_pm_poweroff,
519 .restore = nvhost_pm_restore,
520 .suspend_noirq = nvhost_pm_suspend_noirq,
521 .resume_noirq = nvhost_pm_resume_noirq,
522 .freeze_noirq = nvhost_pm_freeze_noirq,
523 .thaw_noirq = nvhost_pm_thaw_noirq,
524 .poweroff_noirq = nvhost_pm_poweroff_noirq,
525 .restore_noirq = nvhost_pm_restore_noirq,
526 .runtime_suspend = nvhost_pm_runtime_suspend,
527 .runtime_resume = nvhost_pm_runtime_resume,
528 .runtime_idle = nvhost_pm_runtime_idle,
529};
530
531struct bus_type nvhost_bus_type = {
532 .name = "nvhost",
533 .match = nvhost_bus_match,
534 .pm = &nvhost_dev_pm_ops,
535};
536EXPORT_SYMBOL(nvhost_bus_type);
537
538static int set_parent(struct device *dev, void *data)
539{
540 struct nvhost_device *ndev = to_nvhost_device(dev);
541 struct nvhost_master *host = data;
542 if (!dev->parent && ndev != host->dev)
543 dev->parent = &host->dev->dev;
544 return 0;
545}
546
547int nvhost_bus_add_host(struct nvhost_master *host)
548{
549 nvhost = host;
550
551 /* Assign host1x as parent to all devices in nvhost bus */
552 bus_for_each_dev(&nvhost_bus_type, NULL, host, set_parent);
553
554 return 0;
555}
556
557
558int nvhost_bus_init(void)
559{
560 int err;
561
562 pr_info("host1x bus init\n");
563
564 err = bus_register(&nvhost_bus_type);
565
566 return err;
567}
568postcore_initcall(nvhost_bus_init);
569
diff --git a/drivers/video/tegra/host/bus_client.c b/drivers/video/tegra/host/bus_client.c
new file mode 100644
index 00000000000..940f04a40e8
--- /dev/null
+++ b/drivers/video/tegra/host/bus_client.c
@@ -0,0 +1,606 @@
1/*
2 * drivers/video/tegra/host/bus_client.c
3 *
4 * Tegra Graphics Host Client Module
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/slab.h>
22#include <linux/string.h>
23#include <linux/spinlock.h>
24#include <linux/fs.h>
25#include <linux/cdev.h>
26#include <linux/uaccess.h>
27#include <linux/file.h>
28#include <linux/clk.h>
29#include <linux/hrtimer.h>
30
31#include <trace/events/nvhost.h>
32
33#include <linux/io.h>
34#include <linux/string.h>
35
36#include <linux/nvhost.h>
37#include <linux/nvhost_ioctl.h>
38
39#include <mach/nvmap.h>
40#include <mach/gpufuse.h>
41#include <mach/hardware.h>
42#include <mach/iomap.h>
43
44#include "debug.h"
45#include "bus_client.h"
46#include "dev.h"
47
48void nvhost_read_module_regs(struct nvhost_device *ndev,
49 u32 offset, int count, u32 *values)
50{
51 void __iomem *p = ndev->aperture + offset;
52
53 nvhost_module_busy(ndev);
54 while (count--) {
55 *(values++) = readl(p);
56 p += 4;
57 }
58 rmb();
59 nvhost_module_idle(ndev);
60}
61
62void nvhost_write_module_regs(struct nvhost_device *ndev,
63 u32 offset, int count, const u32 *values)
64{
65 void __iomem *p = ndev->aperture + offset;
66
67 nvhost_module_busy(ndev);
68 while (count--) {
69 writel(*(values++), p);
70 p += 4;
71 }
72 wmb();
73 nvhost_module_idle(ndev);
74}
75
76struct nvhost_channel_userctx {
77 struct nvhost_channel *ch;
78 struct nvhost_hwctx *hwctx;
79 struct nvhost_submit_hdr_ext hdr;
80 int num_relocshifts;
81 struct nvhost_job *job;
82 struct nvmap_client *nvmap;
83 u32 timeout;
84 u32 priority;
85 int clientid;
86};
87
88/*
89 * Write cmdbuf to ftrace output. Checks if cmdbuf contents should be output
90 * and mmaps the cmdbuf contents if required.
91 */
92static void trace_write_cmdbufs(struct nvhost_job *job)
93{
94 struct nvmap_handle_ref handle;
95 void *mem = NULL;
96 int i = 0;
97
98 for (i = 0; i < job->num_gathers; i++) {
99 struct nvhost_channel_gather *gather = &job->gathers[i];
100 if (nvhost_debug_trace_cmdbuf) {
101 handle.handle = nvmap_id_to_handle(gather->mem_id);
102 mem = nvmap_mmap(&handle);
103 if (IS_ERR_OR_NULL(mem))
104 mem = NULL;
105 };
106
107 if (mem) {
108 u32 i;
109 /*
110 * Write in batches of 128 as there seems to be a limit
111 * of how much you can output to ftrace at once.
112 */
113 for (i = 0; i < gather->words; i += TRACE_MAX_LENGTH) {
114 trace_nvhost_channel_write_cmdbuf_data(
115 job->ch->dev->name,
116 gather->mem_id,
117 min(gather->words - i,
118 TRACE_MAX_LENGTH),
119 gather->offset + i * sizeof(u32),
120 mem);
121 }
122 nvmap_munmap(&handle, mem);
123 }
124 }
125}
126
127static int nvhost_channelrelease(struct inode *inode, struct file *filp)
128{
129 struct nvhost_channel_userctx *priv = filp->private_data;
130
131 trace_nvhost_channel_release(priv->ch->dev->name);
132
133 filp->private_data = NULL;
134
135 nvhost_module_remove_client(priv->ch->dev, priv);
136 nvhost_putchannel(priv->ch, priv->hwctx);
137
138 if (priv->hwctx)
139 priv->ch->ctxhandler->put(priv->hwctx);
140
141 if (priv->job)
142 nvhost_job_put(priv->job);
143
144 nvmap_client_put(priv->nvmap);
145 kfree(priv);
146 return 0;
147}
148
149static int nvhost_channelopen(struct inode *inode, struct file *filp)
150{
151 struct nvhost_channel_userctx *priv;
152 struct nvhost_channel *ch;
153
154 ch = container_of(inode->i_cdev, struct nvhost_channel, cdev);
155 ch = nvhost_getchannel(ch);
156 if (!ch)
157 return -ENOMEM;
158 trace_nvhost_channel_open(ch->dev->name);
159
160 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
161 if (!priv) {
162 nvhost_putchannel(ch, NULL);
163 return -ENOMEM;
164 }
165 filp->private_data = priv;
166 priv->ch = ch;
167 nvhost_module_add_client(ch->dev, priv);
168
169 if (ch->ctxhandler && ch->ctxhandler->alloc) {
170 priv->hwctx = ch->ctxhandler->alloc(ch->ctxhandler, ch);
171 if (!priv->hwctx)
172 goto fail;
173 }
174 priv->priority = NVHOST_PRIORITY_MEDIUM;
175 priv->clientid = atomic_add_return(1,
176 &nvhost_get_host(ch->dev)->clientid);
177
178 priv->job = nvhost_job_alloc(ch, priv->hwctx, &priv->hdr,
179 NULL, priv->priority, priv->clientid);
180 if (!priv->job)
181 goto fail;
182
183 return 0;
184fail:
185 nvhost_channelrelease(inode, filp);
186 return -ENOMEM;
187}
188
189static int set_submit(struct nvhost_channel_userctx *ctx)
190{
191 struct device *device = &ctx->ch->dev->dev;
192
193 /* submit should have at least 1 cmdbuf */
194 if (!ctx->hdr.num_cmdbufs)
195 return -EIO;
196
197 if (!ctx->nvmap) {
198 dev_err(device, "no nvmap context set\n");
199 return -EFAULT;
200 }
201
202 ctx->job = nvhost_job_realloc(ctx->job,
203 ctx->hwctx,
204 &ctx->hdr,
205 ctx->nvmap,
206 ctx->priority,
207 ctx->clientid);
208 if (!ctx->job)
209 return -ENOMEM;
210 ctx->job->timeout = ctx->timeout;
211
212 if (ctx->hdr.submit_version >= NVHOST_SUBMIT_VERSION_V2)
213 ctx->num_relocshifts = ctx->hdr.num_relocs;
214
215 return 0;
216}
217
218static void reset_submit(struct nvhost_channel_userctx *ctx)
219{
220 ctx->hdr.num_cmdbufs = 0;
221 ctx->hdr.num_relocs = 0;
222 ctx->num_relocshifts = 0;
223 ctx->hdr.num_waitchks = 0;
224}
225
226static ssize_t nvhost_channelwrite(struct file *filp, const char __user *buf,
227 size_t count, loff_t *offp)
228{
229 struct nvhost_channel_userctx *priv = filp->private_data;
230 size_t remaining = count;
231 int err = 0;
232 struct nvhost_job *job = priv->job;
233 struct nvhost_submit_hdr_ext *hdr = &priv->hdr;
234 const char *chname = priv->ch->dev->name;
235
236 if (!job)
237 return -EIO;
238
239 while (remaining) {
240 size_t consumed;
241 if (!hdr->num_relocs &&
242 !priv->num_relocshifts &&
243 !hdr->num_cmdbufs &&
244 !hdr->num_waitchks) {
245 consumed = sizeof(struct nvhost_submit_hdr);
246 if (remaining < consumed)
247 break;
248 if (copy_from_user(hdr, buf, consumed)) {
249 err = -EFAULT;
250 break;
251 }
252 hdr->submit_version = NVHOST_SUBMIT_VERSION_V0;
253 err = set_submit(priv);
254 if (err)
255 break;
256 trace_nvhost_channel_write_submit(chname,
257 count, hdr->num_cmdbufs, hdr->num_relocs,
258 hdr->syncpt_id, hdr->syncpt_incrs);
259 } else if (hdr->num_cmdbufs) {
260 struct nvhost_cmdbuf cmdbuf;
261 consumed = sizeof(cmdbuf);
262 if (remaining < consumed)
263 break;
264 if (copy_from_user(&cmdbuf, buf, consumed)) {
265 err = -EFAULT;
266 break;
267 }
268 trace_nvhost_channel_write_cmdbuf(chname,
269 cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
270 nvhost_job_add_gather(job,
271 cmdbuf.mem, cmdbuf.words, cmdbuf.offset);
272 hdr->num_cmdbufs--;
273 } else if (hdr->num_relocs) {
274 consumed = sizeof(struct nvhost_reloc);
275 if (remaining < consumed)
276 break;
277 if (copy_from_user(&job->pinarray[job->num_pins],
278 buf, consumed)) {
279 err = -EFAULT;
280 break;
281 }
282 trace_nvhost_channel_write_reloc(chname);
283 job->num_pins++;
284 hdr->num_relocs--;
285 } else if (hdr->num_waitchks) {
286 int numwaitchks =
287 (remaining / sizeof(struct nvhost_waitchk));
288 if (!numwaitchks)
289 break;
290 numwaitchks = min_t(int,
291 numwaitchks, hdr->num_waitchks);
292 consumed = numwaitchks * sizeof(struct nvhost_waitchk);
293 if (copy_from_user(&job->waitchk[job->num_waitchk],
294 buf, consumed)) {
295 err = -EFAULT;
296 break;
297 }
298 trace_nvhost_channel_write_waitchks(
299 chname, numwaitchks,
300 hdr->waitchk_mask);
301 job->num_waitchk += numwaitchks;
302 hdr->num_waitchks -= numwaitchks;
303 } else if (priv->num_relocshifts) {
304 int next_shift =
305 job->num_pins - priv->num_relocshifts;
306 consumed = sizeof(struct nvhost_reloc_shift);
307 if (remaining < consumed)
308 break;
309 if (copy_from_user(
310 &job->pinarray[next_shift].reloc_shift,
311 buf, consumed)) {
312 err = -EFAULT;
313 break;
314 }
315 priv->num_relocshifts--;
316 } else {
317 err = -EFAULT;
318 break;
319 }
320 remaining -= consumed;
321 buf += consumed;
322 }
323
324 if (err < 0) {
325 dev_err(&priv->ch->dev->dev, "channel write error\n");
326 reset_submit(priv);
327 return err;
328 }
329
330 return count - remaining;
331}
332
333static int nvhost_ioctl_channel_flush(
334 struct nvhost_channel_userctx *ctx,
335 struct nvhost_get_param_args *args,
336 int null_kickoff)
337{
338 struct device *device = &ctx->ch->dev->dev;
339 int err;
340
341 trace_nvhost_ioctl_channel_flush(ctx->ch->dev->name);
342
343 if (!ctx->job ||
344 ctx->hdr.num_relocs ||
345 ctx->hdr.num_cmdbufs ||
346 ctx->hdr.num_waitchks) {
347 reset_submit(ctx);
348 dev_err(device, "channel submit out of sync\n");
349 return -EFAULT;
350 }
351
352 err = nvhost_job_pin(ctx->job);
353 if (err) {
354 dev_warn(device, "nvhost_job_pin failed: %d\n", err);
355 return err;
356 }
357
358 if (nvhost_debug_null_kickoff_pid == current->tgid)
359 null_kickoff = 1;
360 ctx->job->null_kickoff = null_kickoff;
361
362 if ((nvhost_debug_force_timeout_pid == current->tgid) &&
363 (nvhost_debug_force_timeout_channel == ctx->ch->chid)) {
364 ctx->timeout = nvhost_debug_force_timeout_val;
365 }
366
367 trace_write_cmdbufs(ctx->job);
368
369 /* context switch if needed, and submit user's gathers to the channel */
370 err = nvhost_channel_submit(ctx->job);
371 args->value = ctx->job->syncpt_end;
372 if (err)
373 nvhost_job_unpin(ctx->job);
374
375 return err;
376}
377
378static int nvhost_ioctl_channel_read_3d_reg(
379 struct nvhost_channel_userctx *ctx,
380 struct nvhost_read_3d_reg_args *args)
381{
382 BUG_ON(!channel_op(ctx->ch).read3dreg);
383 return channel_op(ctx->ch).read3dreg(ctx->ch, ctx->hwctx,
384 args->offset, &args->value);
385}
386
387static long nvhost_channelctl(struct file *filp,
388 unsigned int cmd, unsigned long arg)
389{
390 struct nvhost_channel_userctx *priv = filp->private_data;
391 u8 buf[NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE];
392 int err = 0;
393
394 if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
395 (_IOC_NR(cmd) == 0) ||
396 (_IOC_NR(cmd) > NVHOST_IOCTL_CHANNEL_LAST))
397 return -EFAULT;
398
399 BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CHANNEL_MAX_ARG_SIZE);
400
401 if (_IOC_DIR(cmd) & _IOC_WRITE) {
402 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
403 return -EFAULT;
404 }
405
406 switch (cmd) {
407 case NVHOST_IOCTL_CHANNEL_FLUSH:
408 err = nvhost_ioctl_channel_flush(priv, (void *)buf, 0);
409 break;
410 case NVHOST_IOCTL_CHANNEL_NULL_KICKOFF:
411 err = nvhost_ioctl_channel_flush(priv, (void *)buf, 1);
412 break;
413 case NVHOST_IOCTL_CHANNEL_SUBMIT_EXT:
414 {
415 struct nvhost_submit_hdr_ext *hdr;
416
417 if (priv->hdr.num_relocs ||
418 priv->num_relocshifts ||
419 priv->hdr.num_cmdbufs ||
420 priv->hdr.num_waitchks) {
421 reset_submit(priv);
422 dev_err(&priv->ch->dev->dev,
423 "channel submit out of sync\n");
424 err = -EIO;
425 break;
426 }
427
428 hdr = (struct nvhost_submit_hdr_ext *)buf;
429 if (hdr->submit_version > NVHOST_SUBMIT_VERSION_MAX_SUPPORTED) {
430 dev_err(&priv->ch->dev->dev,
431 "submit version %d > max supported %d\n",
432 hdr->submit_version,
433 NVHOST_SUBMIT_VERSION_MAX_SUPPORTED);
434 err = -EINVAL;
435 break;
436 }
437 memcpy(&priv->hdr, hdr, sizeof(struct nvhost_submit_hdr_ext));
438 err = set_submit(priv);
439 trace_nvhost_ioctl_channel_submit(priv->ch->dev->name,
440 priv->hdr.submit_version,
441 priv->hdr.num_cmdbufs, priv->hdr.num_relocs,
442 priv->hdr.num_waitchks,
443 priv->hdr.syncpt_id, priv->hdr.syncpt_incrs);
444 break;
445 }
446 case NVHOST_IOCTL_CHANNEL_GET_SYNCPOINTS:
447 /* host syncpt ID is used by the RM (and never be given out) */
448 BUG_ON(priv->ch->dev->syncpts & (1 << NVSYNCPT_GRAPHICS_HOST));
449 ((struct nvhost_get_param_args *)buf)->value =
450 priv->ch->dev->syncpts;
451 break;
452 case NVHOST_IOCTL_CHANNEL_GET_WAITBASES:
453 ((struct nvhost_get_param_args *)buf)->value =
454 priv->ch->dev->waitbases;
455 break;
456 case NVHOST_IOCTL_CHANNEL_GET_MODMUTEXES:
457 ((struct nvhost_get_param_args *)buf)->value =
458 priv->ch->dev->modulemutexes;
459 break;
460 case NVHOST_IOCTL_CHANNEL_SET_NVMAP_FD:
461 {
462 int fd = (int)((struct nvhost_set_nvmap_fd_args *)buf)->fd;
463 struct nvmap_client *new_client = nvmap_client_get_file(fd);
464
465 if (IS_ERR(new_client)) {
466 err = PTR_ERR(new_client);
467 break;
468 }
469
470 if (priv->nvmap)
471 nvmap_client_put(priv->nvmap);
472
473 priv->nvmap = new_client;
474 break;
475 }
476 case NVHOST_IOCTL_CHANNEL_READ_3D_REG:
477 err = nvhost_ioctl_channel_read_3d_reg(priv, (void *)buf);
478 break;
479 case NVHOST_IOCTL_CHANNEL_GET_CLK_RATE:
480 {
481 unsigned long rate;
482 struct nvhost_clk_rate_args *arg =
483 (struct nvhost_clk_rate_args *)buf;
484
485 err = nvhost_module_get_rate(priv->ch->dev, &rate, 0);
486 if (err == 0)
487 arg->rate = rate;
488 break;
489 }
490 case NVHOST_IOCTL_CHANNEL_SET_CLK_RATE:
491 {
492 struct nvhost_clk_rate_args *arg =
493 (struct nvhost_clk_rate_args *)buf;
494 unsigned long rate = (unsigned long)arg->rate;
495
496 err = nvhost_module_set_rate(priv->ch->dev, priv, rate, 0);
497 break;
498 }
499 case NVHOST_IOCTL_CHANNEL_SET_TIMEOUT:
500 priv->timeout =
501 (u32)((struct nvhost_set_timeout_args *)buf)->timeout;
502 dev_dbg(&priv->ch->dev->dev,
503 "%s: setting buffer timeout (%d ms) for userctx 0x%p\n",
504 __func__, priv->timeout, priv);
505 break;
506 case NVHOST_IOCTL_CHANNEL_GET_TIMEDOUT:
507 ((struct nvhost_get_param_args *)buf)->value =
508 priv->hwctx->has_timedout;
509 break;
510 case NVHOST_IOCTL_CHANNEL_SET_PRIORITY:
511 priv->priority =
512 (u32)((struct nvhost_set_priority_args *)buf)->priority;
513 break;
514 default:
515 err = -ENOTTY;
516 break;
517 }
518
519 if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
520 err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
521
522 return err;
523}
524
525static const struct file_operations nvhost_channelops = {
526 .owner = THIS_MODULE,
527 .release = nvhost_channelrelease,
528 .open = nvhost_channelopen,
529 .write = nvhost_channelwrite,
530 .unlocked_ioctl = nvhost_channelctl
531};
532
533int nvhost_client_user_init(struct nvhost_device *dev)
534{
535 int err, devno;
536
537 struct nvhost_channel *ch = dev->channel;
538
539 cdev_init(&ch->cdev, &nvhost_channelops);
540 ch->cdev.owner = THIS_MODULE;
541
542 devno = MKDEV(nvhost_major, nvhost_minor + dev->index);
543 err = cdev_add(&ch->cdev, devno, 1);
544 if (err < 0) {
545 dev_err(&dev->dev,
546 "failed to add chan %i cdev\n", dev->index);
547 goto fail;
548 }
549 ch->node = device_create(nvhost_get_host(dev)->nvhost_class, NULL, devno, NULL,
550 IFACE_NAME "-%s", dev->name);
551 if (IS_ERR(ch->node)) {
552 err = PTR_ERR(ch->node);
553 dev_err(&dev->dev,
554 "failed to create %s channel device\n", dev->name);
555 goto fail;
556 }
557
558 return 0;
559fail:
560 return err;
561}
562
563int nvhost_client_device_init(struct nvhost_device *dev)
564{
565 int err;
566 struct nvhost_master *nvhost_master = nvhost_get_host(dev);
567 struct nvhost_channel *ch = &nvhost_master->channels[dev->index];
568
569 /* store the pointer to this device for channel */
570 ch->dev = dev;
571
572 err = nvhost_channel_init(ch, nvhost_master, dev->index);
573 if (err)
574 goto fail;
575
576 err = nvhost_client_user_init(dev);
577 if (err)
578 goto fail;
579
580 err = nvhost_module_init(dev);
581 if (err)
582 goto fail;
583
584 dev_info(&dev->dev, "initialized\n");
585
586 return 0;
587
588fail:
589 /* Add clean-up */
590 return err;
591}
592
593int nvhost_client_device_suspend(struct nvhost_device *dev)
594{
595 int ret = 0;
596
597 dev_info(&dev->dev, "suspending\n");
598
599 ret = nvhost_channel_suspend(dev->channel);
600 if (ret)
601 return ret;
602
603 dev_info(&dev->dev, "suspend status: %d\n", ret);
604
605 return ret;
606}
diff --git a/drivers/video/tegra/host/bus_client.h b/drivers/video/tegra/host/bus_client.h
new file mode 100644
index 00000000000..4e47071fd14
--- /dev/null
+++ b/drivers/video/tegra/host/bus_client.h
@@ -0,0 +1,39 @@
1/*
2 * drivers/video/tegra/host/bus_client.h
3 *
4 * Tegra Graphics Host client
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_BUS_CLIENT_H
22#define __NVHOST_BUS_CLIENT_H
23
24#include <linux/types.h>
25struct nvhost_device;
26
27void nvhost_read_module_regs(struct nvhost_device *ndev,
28 u32 offset, int count, u32 *values);
29
30void nvhost_write_module_regs(struct nvhost_device *ndev,
31 u32 offset, int count, const u32 *values);
32
33int nvhost_client_user_init(struct nvhost_device *dev);
34
35int nvhost_client_device_init(struct nvhost_device *dev);
36
37int nvhost_client_device_suspend(struct nvhost_device *dev);
38
39#endif
diff --git a/drivers/video/tegra/host/chip_support.h b/drivers/video/tegra/host/chip_support.h
new file mode 100644
index 00000000000..6727e7a69fb
--- /dev/null
+++ b/drivers/video/tegra/host/chip_support.h
@@ -0,0 +1,141 @@
1/*
2 * drivers/video/tegra/host/chip_support.h
3 *
4 * Tegra Graphics Host Chip Support
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#ifndef _NVHOST_CHIP_SUPPORT_H_
21#define _NVHOST_CHIP_SUPPORT_H_
22
23#include <linux/types.h>
24struct output;
25struct nvhost_waitchk;
26struct nvhost_userctx_timeout;
27struct nvhost_master;
28struct nvhost_channel;
29struct nvmap_handle;
30struct nvmap_client;
31struct nvhost_hwctx;
32struct nvhost_cdma;
33struct nvhost_intr;
34struct push_buffer;
35struct nvhost_syncpt;
36struct nvhost_master;
37struct dentry;
38struct nvhost_job;
39
40struct nvhost_chip_support {
41 struct {
42 int (*init)(struct nvhost_channel *,
43 struct nvhost_master *,
44 int chid);
45 int (*submit)(struct nvhost_job *job);
46 int (*read3dreg)(struct nvhost_channel *channel,
47 struct nvhost_hwctx *hwctx,
48 u32 offset,
49 u32 *value);
50 } channel;
51
52 struct {
53 void (*start)(struct nvhost_cdma *);
54 void (*stop)(struct nvhost_cdma *);
55 void (*kick)(struct nvhost_cdma *);
56 int (*timeout_init)(struct nvhost_cdma *,
57 u32 syncpt_id);
58 void (*timeout_destroy)(struct nvhost_cdma *);
59 void (*timeout_teardown_begin)(struct nvhost_cdma *);
60 void (*timeout_teardown_end)(struct nvhost_cdma *,
61 u32 getptr);
62 void (*timeout_cpu_incr)(struct nvhost_cdma *,
63 u32 getptr,
64 u32 syncpt_incrs,
65 u32 syncval,
66 u32 nr_slots);
67 void (*timeout_pb_incr)(struct nvhost_cdma *,
68 u32 getptr,
69 u32 syncpt_incrs,
70 u32 nr_slots,
71 bool exec_ctxsave);
72 } cdma;
73
74 struct {
75 void (*reset)(struct push_buffer *);
76 int (*init)(struct push_buffer *);
77 void (*destroy)(struct push_buffer *);
78 void (*push_to)(struct push_buffer *,
79 struct nvmap_client *,
80 struct nvmap_handle *,
81 u32 op1, u32 op2);
82 void (*pop_from)(struct push_buffer *,
83 unsigned int slots);
84 u32 (*space)(struct push_buffer *);
85 u32 (*putptr)(struct push_buffer *);
86 } push_buffer;
87
88 struct {
89 void (*debug_init)(struct dentry *de);
90 void (*show_channel_cdma)(struct nvhost_master *,
91 struct nvhost_channel *,
92 struct output *,
93 int chid);
94 void (*show_channel_fifo)(struct nvhost_master *,
95 struct nvhost_channel *,
96 struct output *,
97 int chid);
98 void (*show_mlocks)(struct nvhost_master *m,
99 struct output *o);
100
101 } debug;
102
103 struct {
104 void (*reset)(struct nvhost_syncpt *, u32 id);
105 void (*reset_wait_base)(struct nvhost_syncpt *, u32 id);
106 void (*read_wait_base)(struct nvhost_syncpt *, u32 id);
107 u32 (*update_min)(struct nvhost_syncpt *, u32 id);
108 void (*cpu_incr)(struct nvhost_syncpt *, u32 id);
109 int (*wait_check)(struct nvhost_syncpt *sp,
110 struct nvmap_client *nvmap,
111 u32 waitchk_mask,
112 struct nvhost_waitchk *wait,
113 int num_waitchk);
114 void (*debug)(struct nvhost_syncpt *);
115 const char * (*name)(struct nvhost_syncpt *, u32 id);
116 int (*mutex_try_lock)(struct nvhost_syncpt *,
117 unsigned int idx);
118 void (*mutex_unlock)(struct nvhost_syncpt *,
119 unsigned int idx);
120 } syncpt;
121
122 struct {
123 void (*init_host_sync)(struct nvhost_intr *);
124 void (*set_host_clocks_per_usec)(
125 struct nvhost_intr *, u32 clocks);
126 void (*set_syncpt_threshold)(
127 struct nvhost_intr *, u32 id, u32 thresh);
128 void (*enable_syncpt_intr)(struct nvhost_intr *, u32 id);
129 void (*disable_all_syncpt_intrs)(struct nvhost_intr *);
130 int (*request_host_general_irq)(struct nvhost_intr *);
131 void (*free_host_general_irq)(struct nvhost_intr *);
132 int (*request_syncpt_irq)(struct nvhost_intr_syncpt *syncpt);
133 } intr;
134
135 struct {
136 struct nvhost_device *(*get_nvhost_device)(struct nvhost_master *host,
137 char *name);
138 } nvhost_dev;
139};
140
141#endif /* _NVHOST_CHIP_SUPPORT_H_ */
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
new file mode 100644
index 00000000000..91436c903fc
--- /dev/null
+++ b/drivers/video/tegra/host/debug.c
@@ -0,0 +1,167 @@
1/*
2 * drivers/video/tegra/host/debug.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/debugfs.h>
21#include <linux/seq_file.h>
22
23#include <linux/io.h>
24
25#include "dev.h"
26#include "debug.h"
27
28pid_t nvhost_debug_null_kickoff_pid;
29unsigned int nvhost_debug_trace_cmdbuf;
30
31pid_t nvhost_debug_force_timeout_pid;
32u32 nvhost_debug_force_timeout_val;
33u32 nvhost_debug_force_timeout_channel;
34
35void nvhost_debug_output(struct output *o, const char* fmt, ...)
36{
37 va_list args;
38 int len;
39
40 va_start(args, fmt);
41 len = vsnprintf(o->buf, sizeof(o->buf), fmt, args);
42 va_end(args);
43 o->fn(o->ctx, o->buf, len);
44}
45
46static int show_channels(struct device *dev, void *data)
47{
48 struct nvhost_channel *ch;
49 struct nvhost_device *nvdev = to_nvhost_device(dev);
50 struct output *o = data;
51 struct nvhost_master *m;
52
53 if (nvdev == NULL)
54 return 0;
55
56 m = nvhost_get_host(nvdev);
57 ch = nvdev->channel;
58 if (ch) {
59 mutex_lock(&ch->reflock);
60 if (ch->refcount) {
61 mutex_lock(&ch->cdma.lock);
62 m->op.debug.show_channel_fifo(m, ch, o, nvdev->index);
63 m->op.debug.show_channel_cdma(m, ch, o, nvdev->index);
64 mutex_unlock(&ch->cdma.lock);
65 }
66 mutex_unlock(&ch->reflock);
67 }
68
69 return 0;
70}
71
72static void show_syncpts(struct nvhost_master *m, struct output *o)
73{
74 int i;
75 BUG_ON(!m->op.syncpt.name);
76 nvhost_debug_output(o, "---- syncpts ----\n");
77 for (i = 0; i < m->syncpt.nb_pts; i++) {
78 u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
79 u32 min = nvhost_syncpt_update_min(&m->syncpt, i);
80 if (!min && !max)
81 continue;
82 nvhost_debug_output(o, "id %d (%s) min %d max %d\n",
83 i, m->op.syncpt.name(&m->syncpt, i),
84 min, max);
85 }
86
87 for (i = 0; i < m->syncpt.nb_bases; i++) {
88 u32 base_val;
89 base_val = nvhost_syncpt_read_wait_base(&m->syncpt, i);
90 if (base_val)
91 nvhost_debug_output(o, "waitbase id %d val %d\n",
92 i, base_val);
93 }
94
95 nvhost_debug_output(o, "\n");
96}
97
98static void show_all(struct nvhost_master *m, struct output *o)
99{
100 nvhost_module_busy(m->dev);
101
102 m->op.debug.show_mlocks(m, o);
103 show_syncpts(m, o);
104 nvhost_debug_output(o, "---- channels ----\n");
105 bus_for_each_dev(&nvhost_bus_type, NULL, o, show_channels);
106
107 nvhost_module_idle(m->dev);
108}
109
110#ifdef CONFIG_DEBUG_FS
111static int nvhost_debug_show(struct seq_file *s, void *unused)
112{
113 struct output o = {
114 .fn = write_to_seqfile,
115 .ctx = s
116 };
117 show_all(s->private, &o);
118 return 0;
119}
120
121static int nvhost_debug_open(struct inode *inode, struct file *file)
122{
123 return single_open(file, nvhost_debug_show, inode->i_private);
124}
125
126static const struct file_operations nvhost_debug_fops = {
127 .open = nvhost_debug_open,
128 .read = seq_read,
129 .llseek = seq_lseek,
130 .release = single_release,
131};
132
133void nvhost_debug_init(struct nvhost_master *master)
134{
135 struct dentry *de = debugfs_create_dir("tegra_host", NULL);
136
137 debugfs_create_file("status", S_IRUGO, de,
138 master, &nvhost_debug_fops);
139
140 debugfs_create_u32("null_kickoff_pid", S_IRUGO|S_IWUSR, de,
141 &nvhost_debug_null_kickoff_pid);
142 debugfs_create_u32("trace_cmdbuf", S_IRUGO|S_IWUSR, de,
143 &nvhost_debug_trace_cmdbuf);
144
145 if (master->op.debug.debug_init)
146 master->op.debug.debug_init(de);
147
148 debugfs_create_u32("force_timeout_pid", S_IRUGO|S_IWUSR, de,
149 &nvhost_debug_force_timeout_pid);
150 debugfs_create_u32("force_timeout_val", S_IRUGO|S_IWUSR, de,
151 &nvhost_debug_force_timeout_val);
152 debugfs_create_u32("force_timeout_channel", S_IRUGO|S_IWUSR, de,
153 &nvhost_debug_force_timeout_channel);
154}
155#else
156void nvhost_debug_init(struct nvhost_master *master)
157{
158}
159#endif
160
161void nvhost_debug_dump(struct nvhost_master *master)
162{
163 struct output o = {
164 .fn = write_to_printk
165 };
166 show_all(master, &o);
167}
diff --git a/drivers/video/tegra/host/debug.h b/drivers/video/tegra/host/debug.h
new file mode 100644
index 00000000000..3dc156ab474
--- /dev/null
+++ b/drivers/video/tegra/host/debug.h
@@ -0,0 +1,50 @@
1/*
2 * drivers/video/tegra/host/debug.h
3 *
4 * Tegra Graphics Host Debug
5 *
6 * Copyright (c) 2011-2012 NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#ifndef __NVHOST_DEBUG_H
21#define __NVHOST_DEBUG_H
22
23#include <linux/debugfs.h>
24#include <linux/seq_file.h>
25
26struct output {
27 void (*fn)(void *ctx, const char* str, size_t len);
28 void *ctx;
29 char buf[256];
30};
31
32static inline void write_to_seqfile(void *ctx, const char* str, size_t len)
33{
34 seq_write((struct seq_file *)ctx, str, len);
35}
36
37static inline void write_to_printk(void *ctx, const char* str, size_t len)
38{
39 printk(KERN_INFO "%s", str);
40}
41
42void nvhost_debug_output(struct output *o, const char* fmt, ...);
43
44extern pid_t nvhost_debug_null_kickoff_pid;
45extern pid_t nvhost_debug_force_timeout_pid;
46extern u32 nvhost_debug_force_timeout_val;
47extern u32 nvhost_debug_force_timeout_channel;
48extern unsigned int nvhost_debug_trace_cmdbuf;
49
50#endif /*__NVHOST_DEBUG_H */
diff --git a/drivers/video/tegra/host/dev.c b/drivers/video/tegra/host/dev.c
new file mode 100644
index 00000000000..8f0c0393401
--- /dev/null
+++ b/drivers/video/tegra/host/dev.c
@@ -0,0 +1,635 @@
1/*
2 * drivers/video/tegra/host/dev.c
3 *
4 * Tegra Graphics Host Driver Entrypoint
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/slab.h>
22#include <linux/string.h>
23#include <linux/spinlock.h>
24#include <linux/fs.h>
25#include <linux/cdev.h>
26#include <linux/uaccess.h>
27#include <linux/file.h>
28#include <linux/clk.h>
29#include <linux/hrtimer.h>
30
31#include "dev.h"
32#define CREATE_TRACE_POINTS
33#include <trace/events/nvhost.h>
34
35#include <linux/io.h>
36
37#include <linux/nvhost.h>
38#include <linux/nvhost_ioctl.h>
39#include <mach/nvmap.h>
40#include <mach/gpufuse.h>
41#include <mach/hardware.h>
42#include <mach/iomap.h>
43
44#include "debug.h"
45#include "nvhost_job.h"
46#include "t20/t20.h"
47#include "t30/t30.h"
48#include "bus_client.h"
49
50#define DRIVER_NAME "host1x"
51
52int nvhost_major;
53int nvhost_minor;
54
55static unsigned int register_sets;
56
57struct nvhost_ctrl_userctx {
58 struct nvhost_master *dev;
59 u32 *mod_locks;
60};
61
62static int nvhost_ctrlrelease(struct inode *inode, struct file *filp)
63{
64 struct nvhost_ctrl_userctx *priv = filp->private_data;
65 int i;
66
67 trace_nvhost_ctrlrelease(priv->dev->dev->name);
68
69 filp->private_data = NULL;
70 if (priv->mod_locks[0])
71 nvhost_module_idle(priv->dev->dev);
72 for (i = 1; i < priv->dev->syncpt.nb_mlocks; i++)
73 if (priv->mod_locks[i])
74 nvhost_mutex_unlock(&priv->dev->syncpt, i);
75 kfree(priv->mod_locks);
76 kfree(priv);
77 return 0;
78}
79
80static int nvhost_ctrlopen(struct inode *inode, struct file *filp)
81{
82 struct nvhost_master *host = container_of(inode->i_cdev, struct nvhost_master, cdev);
83 struct nvhost_ctrl_userctx *priv;
84 u32 *mod_locks;
85
86 trace_nvhost_ctrlopen(host->dev->name);
87
88 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
89 mod_locks = kzalloc(sizeof(u32) * host->syncpt.nb_mlocks, GFP_KERNEL);
90
91 if (!(priv && mod_locks)) {
92 kfree(priv);
93 kfree(mod_locks);
94 return -ENOMEM;
95 }
96
97 priv->dev = host;
98 priv->mod_locks = mod_locks;
99 filp->private_data = priv;
100 return 0;
101}
102
103static int nvhost_ioctl_ctrl_syncpt_read(struct nvhost_ctrl_userctx *ctx,
104 struct nvhost_ctrl_syncpt_read_args *args)
105{
106 if (args->id >= ctx->dev->syncpt.nb_pts)
107 return -EINVAL;
108 args->value = nvhost_syncpt_read(&ctx->dev->syncpt, args->id);
109 trace_nvhost_ioctl_ctrl_syncpt_read(args->id, args->value);
110 return 0;
111}
112
113static int nvhost_ioctl_ctrl_syncpt_incr(struct nvhost_ctrl_userctx *ctx,
114 struct nvhost_ctrl_syncpt_incr_args *args)
115{
116 if (args->id >= ctx->dev->syncpt.nb_pts)
117 return -EINVAL;
118 trace_nvhost_ioctl_ctrl_syncpt_incr(args->id);
119 nvhost_syncpt_incr(&ctx->dev->syncpt, args->id);
120 return 0;
121}
122
123static int nvhost_ioctl_ctrl_syncpt_waitex(struct nvhost_ctrl_userctx *ctx,
124 struct nvhost_ctrl_syncpt_waitex_args *args)
125{
126 u32 timeout;
127 int err;
128 if (args->id >= ctx->dev->syncpt.nb_pts)
129 return -EINVAL;
130 if (args->timeout == NVHOST_NO_TIMEOUT)
131 timeout = MAX_SCHEDULE_TIMEOUT;
132 else
133 timeout = (u32)msecs_to_jiffies(args->timeout);
134
135 err = nvhost_syncpt_wait_timeout(&ctx->dev->syncpt, args->id,
136 args->thresh, timeout, &args->value);
137 trace_nvhost_ioctl_ctrl_syncpt_wait(args->id, args->thresh,
138 args->timeout, args->value, err);
139
140 return err;
141}
142
143static int nvhost_ioctl_ctrl_module_mutex(struct nvhost_ctrl_userctx *ctx,
144 struct nvhost_ctrl_module_mutex_args *args)
145{
146 int err = 0;
147 if (args->id >= ctx->dev->syncpt.nb_mlocks ||
148 args->lock > 1)
149 return -EINVAL;
150
151 trace_nvhost_ioctl_ctrl_module_mutex(args->lock, args->id);
152 if (args->lock && !ctx->mod_locks[args->id]) {
153 if (args->id == 0)
154 nvhost_module_busy(ctx->dev->dev);
155 else
156 err = nvhost_mutex_try_lock(&ctx->dev->syncpt,
157 args->id);
158 if (!err)
159 ctx->mod_locks[args->id] = 1;
160 } else if (!args->lock && ctx->mod_locks[args->id]) {
161 if (args->id == 0)
162 nvhost_module_idle(ctx->dev->dev);
163 else
164 nvhost_mutex_unlock(&ctx->dev->syncpt, args->id);
165 ctx->mod_locks[args->id] = 0;
166 }
167 return err;
168}
169
170static struct nvhost_device *get_ndev_by_moduleid(struct nvhost_master *host,
171 u32 id)
172{
173 int i;
174
175 for (i = 0; i < host->nb_channels; i++) {
176 struct nvhost_device *ndev = host->channels[i].dev;
177
178 /* display and dsi do not use channel for register programming.
179 * so their channels do not have device instance.
180 * hence skip such channels from here. */
181 if (ndev == NULL)
182 continue;
183
184 if (id == ndev->moduleid)
185 return ndev;
186 }
187 return NULL;
188}
189
190static int nvhost_ioctl_ctrl_module_regrdwr(struct nvhost_ctrl_userctx *ctx,
191 struct nvhost_ctrl_module_regrdwr_args *args)
192{
193 u32 num_offsets = args->num_offsets;
194 u32 *offsets = args->offsets;
195 u32 *values = args->values;
196 u32 vals[64];
197 struct nvhost_device *ndev;
198
199 trace_nvhost_ioctl_ctrl_module_regrdwr(args->id,
200 args->num_offsets, args->write);
201 /* Check that there is something to read and that block size is
202 * u32 aligned */
203 if (num_offsets == 0 || args->block_size & 3)
204 return -EINVAL;
205
206 ndev = get_ndev_by_moduleid(ctx->dev, args->id);
207 if (!ndev)
208 return -EINVAL;
209
210 while (num_offsets--) {
211 int remaining = args->block_size >> 2;
212 u32 offs;
213 if (get_user(offs, offsets))
214 return -EFAULT;
215 offsets++;
216 while (remaining) {
217 int batch = min(remaining, 64);
218 if (args->write) {
219 if (copy_from_user(vals, values,
220 batch*sizeof(u32)))
221 return -EFAULT;
222 nvhost_write_module_regs(ndev,
223 offs, batch, vals);
224 } else {
225 nvhost_read_module_regs(ndev,
226 offs, batch, vals);
227 if (copy_to_user(values, vals,
228 batch*sizeof(u32)))
229 return -EFAULT;
230 }
231 remaining -= batch;
232 offs += batch;
233 values += batch;
234 }
235 }
236
237 return 0;
238}
239
240static int nvhost_ioctl_ctrl_get_version(struct nvhost_ctrl_userctx *ctx,
241 struct nvhost_get_param_args *args)
242{
243 args->value = NVHOST_SUBMIT_VERSION_MAX_SUPPORTED;
244 return 0;
245}
246
247static long nvhost_ctrlctl(struct file *filp,
248 unsigned int cmd, unsigned long arg)
249{
250 struct nvhost_ctrl_userctx *priv = filp->private_data;
251 u8 buf[NVHOST_IOCTL_CTRL_MAX_ARG_SIZE];
252 int err = 0;
253
254 if ((_IOC_TYPE(cmd) != NVHOST_IOCTL_MAGIC) ||
255 (_IOC_NR(cmd) == 0) ||
256 (_IOC_NR(cmd) > NVHOST_IOCTL_CTRL_LAST))
257 return -EFAULT;
258
259 BUG_ON(_IOC_SIZE(cmd) > NVHOST_IOCTL_CTRL_MAX_ARG_SIZE);
260
261 if (_IOC_DIR(cmd) & _IOC_WRITE) {
262 if (copy_from_user(buf, (void __user *)arg, _IOC_SIZE(cmd)))
263 return -EFAULT;
264 }
265
266 switch (cmd) {
267 case NVHOST_IOCTL_CTRL_SYNCPT_READ:
268 err = nvhost_ioctl_ctrl_syncpt_read(priv, (void *)buf);
269 break;
270 case NVHOST_IOCTL_CTRL_SYNCPT_INCR:
271 err = nvhost_ioctl_ctrl_syncpt_incr(priv, (void *)buf);
272 break;
273 case NVHOST_IOCTL_CTRL_SYNCPT_WAIT:
274 err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
275 break;
276 case NVHOST_IOCTL_CTRL_MODULE_MUTEX:
277 err = nvhost_ioctl_ctrl_module_mutex(priv, (void *)buf);
278 break;
279 case NVHOST_IOCTL_CTRL_MODULE_REGRDWR:
280 err = nvhost_ioctl_ctrl_module_regrdwr(priv, (void *)buf);
281 break;
282 case NVHOST_IOCTL_CTRL_SYNCPT_WAITEX:
283 err = nvhost_ioctl_ctrl_syncpt_waitex(priv, (void *)buf);
284 break;
285 case NVHOST_IOCTL_CTRL_GET_VERSION:
286 err = nvhost_ioctl_ctrl_get_version(priv, (void *)buf);
287 break;
288 default:
289 err = -ENOTTY;
290 break;
291 }
292
293 if ((err == 0) && (_IOC_DIR(cmd) & _IOC_READ))
294 err = copy_to_user((void __user *)arg, buf, _IOC_SIZE(cmd));
295
296 return err;
297}
298
299static const struct file_operations nvhost_ctrlops = {
300 .owner = THIS_MODULE,
301 .release = nvhost_ctrlrelease,
302 .open = nvhost_ctrlopen,
303 .unlocked_ioctl = nvhost_ctrlctl
304};
305
306static void power_on_host(struct nvhost_device *dev)
307{
308 struct nvhost_master *host = nvhost_get_drvdata(dev);
309 nvhost_syncpt_reset(&host->syncpt);
310 nvhost_intr_start(&host->intr, clk_get_rate(dev->clk[0]));
311}
312
313static int power_off_host(struct nvhost_device *dev)
314{
315 struct nvhost_master *host = nvhost_get_drvdata(dev);
316 nvhost_syncpt_save(&host->syncpt);
317 nvhost_intr_stop(&host->intr);
318 return 0;
319}
320
321static int __devinit nvhost_user_init(struct nvhost_master *host)
322{
323 int err, devno;
324
325 host->nvhost_class = class_create(THIS_MODULE, IFACE_NAME);
326 if (IS_ERR(host->nvhost_class)) {
327 err = PTR_ERR(host->nvhost_class);
328 dev_err(&host->dev->dev, "failed to create class\n");
329 goto fail;
330 }
331
332 err = alloc_chrdev_region(&devno, nvhost_minor,
333 host->nb_channels + 1, IFACE_NAME);
334 nvhost_major = MAJOR(devno);
335 if (err < 0) {
336 dev_err(&host->dev->dev, "failed to reserve chrdev region\n");
337 goto fail;
338 }
339
340 cdev_init(&host->cdev, &nvhost_ctrlops);
341 host->cdev.owner = THIS_MODULE;
342 devno = MKDEV(nvhost_major, nvhost_minor + host->nb_channels);
343 err = cdev_add(&host->cdev, devno, 1);
344 if (err < 0)
345 goto fail;
346 host->ctrl = device_create(host->nvhost_class, NULL, devno, NULL,
347 IFACE_NAME "-ctrl");
348 if (IS_ERR(host->ctrl)) {
349 err = PTR_ERR(host->ctrl);
350 dev_err(&host->dev->dev, "failed to create ctrl device\n");
351 goto fail;
352 }
353
354 return 0;
355fail:
356 return err;
357}
358
359struct nvhost_device *nvhost_get_device(char *name)
360{
361 BUG_ON(!host_device_op(nvhost).get_nvhost_device);
362 return host_device_op(nvhost).get_nvhost_device(nvhost, name);
363}
364
365static void nvhost_remove_chip_support(struct nvhost_master *host)
366{
367 kfree(host->channels);
368 host->channels = 0;
369
370 kfree(host->syncpt.min_val);
371 host->syncpt.min_val = 0;
372
373 kfree(host->syncpt.max_val);
374 host->syncpt.max_val = 0;
375
376 kfree(host->syncpt.base_val);
377 host->syncpt.base_val = 0;
378
379 kfree(host->intr.syncpt);
380 host->intr.syncpt = 0;
381
382 kfree(host->syncpt.lock_counts);
383 host->syncpt.lock_counts = 0;
384}
385
386static int __devinit nvhost_init_chip_support(struct nvhost_master *host)
387{
388 int err;
389 switch (tegra_get_chipid()) {
390 case TEGRA_CHIPID_TEGRA2:
391 err = nvhost_init_t20_support(host);
392 break;
393
394 case TEGRA_CHIPID_TEGRA3:
395 err = nvhost_init_t30_support(host);
396 break;
397 default:
398 return -ENODEV;
399 }
400
401 if (err)
402 return err;
403
404 /* allocate items sized in chip specific support init */
405 host->channels = kzalloc(sizeof(struct nvhost_channel) *
406 host->nb_channels, GFP_KERNEL);
407
408 host->syncpt.min_val = kzalloc(sizeof(atomic_t) *
409 host->syncpt.nb_pts, GFP_KERNEL);
410
411 host->syncpt.max_val = kzalloc(sizeof(atomic_t) *
412 host->syncpt.nb_pts, GFP_KERNEL);
413
414 host->syncpt.base_val = kzalloc(sizeof(u32) *
415 host->syncpt.nb_bases, GFP_KERNEL);
416
417 host->intr.syncpt = kzalloc(sizeof(struct nvhost_intr_syncpt) *
418 host->syncpt.nb_pts, GFP_KERNEL);
419
420 host->syncpt.lock_counts = kzalloc(sizeof(atomic_t) *
421 host->syncpt.nb_mlocks, GFP_KERNEL);
422
423 if (!(host->channels && host->syncpt.min_val &&
424 host->syncpt.max_val && host->syncpt.base_val &&
425 host->intr.syncpt && host->syncpt.lock_counts)) {
426 /* frees happen in the support removal phase */
427 return -ENOMEM;
428 }
429
430 return 0;
431}
432
433static struct resource nvhost_resources[] = {
434 {
435 .start = TEGRA_HOST1X_BASE,
436 .end = TEGRA_HOST1X_BASE + TEGRA_HOST1X_SIZE - 1,
437 .flags = IORESOURCE_MEM,
438 },
439 {
440 .start = TEGRA_DISPLAY_BASE,
441 .end = TEGRA_DISPLAY_BASE + TEGRA_DISPLAY_SIZE - 1,
442 .flags = IORESOURCE_MEM,
443 },
444 {
445 .start = TEGRA_DISPLAY2_BASE,
446 .end = TEGRA_DISPLAY2_BASE + TEGRA_DISPLAY2_SIZE - 1,
447 .flags = IORESOURCE_MEM,
448 },
449 {
450 .start = TEGRA_VI_BASE,
451 .end = TEGRA_VI_BASE + TEGRA_VI_SIZE - 1,
452 .flags = IORESOURCE_MEM,
453 },
454 {
455 .start = TEGRA_ISP_BASE,
456 .end = TEGRA_ISP_BASE + TEGRA_ISP_SIZE - 1,
457 .flags = IORESOURCE_MEM,
458 },
459 {
460 .start = TEGRA_MPE_BASE,
461 .end = TEGRA_MPE_BASE + TEGRA_MPE_SIZE - 1,
462 .flags = IORESOURCE_MEM,
463 },
464 {
465 .start = INT_SYNCPT_THRESH_BASE,
466 .end = INT_SYNCPT_THRESH_BASE + INT_SYNCPT_THRESH_NR - 1,
467 .flags = IORESOURCE_IRQ,
468 },
469 {
470 .start = INT_HOST1X_MPCORE_GENERAL,
471 .end = INT_HOST1X_MPCORE_GENERAL,
472 .flags = IORESOURCE_IRQ,
473 },
474};
475
476struct nvhost_device tegra_grhost_device = {
477 .name = DRIVER_NAME,
478 .id = -1,
479 .resource = nvhost_resources,
480 .num_resources = ARRAY_SIZE(nvhost_resources),
481 .finalize_poweron = power_on_host,
482 .prepare_poweroff = power_off_host,
483 .clocks = {{"host1x", UINT_MAX}, {} },
484 NVHOST_MODULE_NO_POWERGATE_IDS,
485};
486
487static int __devinit nvhost_probe(struct nvhost_device *dev)
488{
489 struct nvhost_master *host;
490 struct resource *regs, *intr0, *intr1;
491 int i, err;
492
493 regs = nvhost_get_resource(dev, IORESOURCE_MEM, 0);
494 intr0 = nvhost_get_resource(dev, IORESOURCE_IRQ, 0);
495 intr1 = nvhost_get_resource(dev, IORESOURCE_IRQ, 1);
496
497 if (!regs || !intr0 || !intr1) {
498 dev_err(&dev->dev, "missing required platform resources\n");
499 return -ENXIO;
500 }
501
502 host = kzalloc(sizeof(*host), GFP_KERNEL);
503 if (!host)
504 return -ENOMEM;
505
506 host->nvmap = nvmap_create_client(nvmap_dev, "nvhost");
507 if (!host->nvmap) {
508 dev_err(&dev->dev, "unable to create nvmap client\n");
509 err = -EIO;
510 goto fail;
511 }
512
513 host->reg_mem = request_mem_region(regs->start,
514 resource_size(regs), dev->name);
515 if (!host->reg_mem) {
516 dev_err(&dev->dev, "failed to get host register memory\n");
517 err = -ENXIO;
518 goto fail;
519 }
520
521 host->aperture = ioremap(regs->start, resource_size(regs));
522 if (!host->aperture) {
523 dev_err(&dev->dev, "failed to remap host registers\n");
524 err = -ENXIO;
525 goto fail;
526 }
527
528 err = nvhost_init_chip_support(host);
529 if (err) {
530 dev_err(&dev->dev, "failed to init chip support\n");
531 goto fail;
532 }
533
534 /* Register host1x device as bus master */
535 host->dev = dev;
536
537 /* Give pointer to host1x via driver */
538 nvhost_set_drvdata(dev, host);
539
540 nvhost_bus_add_host(host);
541
542 err = nvhost_intr_init(&host->intr, intr1->start, intr0->start);
543 if (err)
544 goto fail;
545
546 err = nvhost_user_init(host);
547 if (err)
548 goto fail;
549
550 err = nvhost_module_init(&tegra_grhost_device);
551 if (err)
552 goto fail;
553
554 for (i = 0; i < host->dev->num_clks; i++)
555 clk_enable(host->dev->clk[i]);
556 nvhost_syncpt_reset(&host->syncpt);
557 for (i = 0; i < host->dev->num_clks; i++)
558 clk_disable(host->dev->clk[0]);
559
560 nvhost_debug_init(host);
561
562 dev_info(&dev->dev, "initialized\n");
563 return 0;
564
565fail:
566 nvhost_remove_chip_support(host);
567 if (host->nvmap)
568 nvmap_client_put(host->nvmap);
569 kfree(host);
570 return err;
571}
572
573static int __exit nvhost_remove(struct nvhost_device *dev)
574{
575 struct nvhost_master *host = nvhost_get_drvdata(dev);
576 nvhost_intr_deinit(&host->intr);
577 nvhost_remove_chip_support(host);
578 return 0;
579}
580
581static int nvhost_suspend(struct nvhost_device *dev, pm_message_t state)
582{
583 struct nvhost_master *host = nvhost_get_drvdata(dev);
584 int ret = 0;
585
586 dev_info(&dev->dev, "suspending\n");
587 ret = nvhost_module_suspend(host->dev, true);
588 dev_info(&dev->dev, "suspend status: %d\n", ret);
589
590 return ret;
591}
592
593static int nvhost_resume(struct nvhost_device *dev)
594{
595 dev_info(&dev->dev, "resuming\n");
596 return 0;
597}
598
599static struct nvhost_driver nvhost_driver = {
600 .probe = nvhost_probe,
601 .remove = __exit_p(nvhost_remove),
602 .suspend = nvhost_suspend,
603 .resume = nvhost_resume,
604 .driver = {
605 .owner = THIS_MODULE,
606 .name = DRIVER_NAME
607 }
608};
609
610static int __init nvhost_mod_init(void)
611{
612 register_sets = tegra_gpu_register_sets();
613 return nvhost_driver_register(&nvhost_driver);
614}
615
616static void __exit nvhost_mod_exit(void)
617{
618 nvhost_driver_unregister(&nvhost_driver);
619}
620
621/* host1x master device needs nvmap to be instantiated first.
622 * nvmap is instantiated via fs_initcall.
623 * Hence instantiate host1x master device using rootfs_initcall
624 * which is one level after fs_initcall. */
625rootfs_initcall(nvhost_mod_init);
626module_exit(nvhost_mod_exit);
627
628module_param_call(register_sets, NULL, param_get_uint, &register_sets, 0444);
629MODULE_PARM_DESC(register_sets, "Number of register sets");
630
631MODULE_AUTHOR("NVIDIA");
632MODULE_DESCRIPTION("Graphics host driver for Tegra products");
633MODULE_VERSION("1.0");
634MODULE_LICENSE("GPL");
635MODULE_ALIAS("platform-nvhost");
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
new file mode 100644
index 00000000000..74d7e16fc27
--- /dev/null
+++ b/drivers/video/tegra/host/dev.h
@@ -0,0 +1,68 @@
1/*
2 * drivers/video/tegra/host/dev.h
3 *
4 * Tegra Graphics Host Driver Entrypoint
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_DEV_H
22#define __NVHOST_DEV_H
23
24#include "nvhost_acm.h"
25#include "nvhost_syncpt.h"
26#include "nvhost_intr.h"
27#include "nvhost_channel.h"
28#include "chip_support.h"
29
30#define TRACE_MAX_LENGTH 128U
31#define IFACE_NAME "nvhost"
32
33extern int nvhost_major;
34extern int nvhost_minor;
35
36struct nvhost_hwctx;
37
38struct nvhost_master {
39 void __iomem *aperture;
40 void __iomem *sync_aperture;
41 struct resource *reg_mem;
42 struct class *nvhost_class;
43 struct cdev cdev;
44 struct device *ctrl;
45 struct nvhost_syncpt syncpt;
46 struct nvmap_client *nvmap;
47 struct nvhost_intr intr;
48 struct nvhost_device *dev;
49 struct nvhost_channel *channels;
50 u32 nb_channels;
51
52 struct nvhost_chip_support op;
53
54 atomic_t clientid;
55};
56
57extern struct nvhost_master *nvhost;
58
59void nvhost_debug_init(struct nvhost_master *master);
60void nvhost_debug_dump(struct nvhost_master *master);
61
62#define host_device_op(host) (host->op.nvhost_dev)
63
64struct nvhost_device *nvhost_get_device(char *name);
65
66extern pid_t nvhost_debug_null_kickoff_pid;
67
68#endif
diff --git a/drivers/video/tegra/host/dsi/Makefile b/drivers/video/tegra/host/dsi/Makefile
new file mode 100644
index 00000000000..eb94d3ec492
--- /dev/null
+++ b/drivers/video/tegra/host/dsi/Makefile
@@ -0,0 +1,7 @@
1GCOV_PROFILE := y
2EXTRA_CFLAGS += -Idrivers/video/tegra/host
3
4nvhost-dsi-objs = \
5 dsi.o
6
7obj-$(CONFIG_TEGRA_GRHOST) += nvhost-dsi.o
diff --git a/drivers/video/tegra/host/dsi/dsi.c b/drivers/video/tegra/host/dsi/dsi.c
new file mode 100644
index 00000000000..0e49f591574
--- /dev/null
+++ b/drivers/video/tegra/host/dsi/dsi.c
@@ -0,0 +1,82 @@
1/*
2 * drivers/video/tegra/host/dsi/dsi.c
3 *
4 * Tegra Graphics DSI
5 *
6 * Copyright (c) 2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "dev.h"
22#include "bus_client.h"
23
24static int dsi_probe(struct nvhost_device *dev)
25{
26 return nvhost_client_device_init(dev);
27}
28
29static int __exit dsi_remove(struct nvhost_device *dev)
30{
31 /* Add clean-up */
32 return 0;
33}
34
35static int dsi_suspend(struct nvhost_device *dev, pm_message_t state)
36{
37 return nvhost_client_device_suspend(dev);
38}
39
40static int dsi_resume(struct nvhost_device *dev)
41{
42 dev_info(&dev->dev, "resuming\n");
43 return 0;
44}
45
46struct nvhost_device *dsi_device;
47
48static struct nvhost_driver dsi_driver = {
49 .probe = dsi_probe,
50 .remove = __exit_p(dsi_remove),
51#ifdef CONFIG_PM
52 .suspend = dsi_suspend,
53 .resume = dsi_resume,
54#endif
55 .driver = {
56 .owner = THIS_MODULE,
57 .name = "dsi",
58 }
59};
60
61static int __init dsi_init(void)
62{
63 int err;
64
65 dsi_device = nvhost_get_device("dsi");
66 if (!dsi_device)
67 return -ENXIO;
68
69 err = nvhost_device_register(dsi_device);
70 if (err)
71 return err;
72
73 return nvhost_driver_register(&dsi_driver);
74}
75
76static void __exit dsi_exit(void)
77{
78 nvhost_driver_unregister(&dsi_driver);
79}
80
81module_init(dsi_init);
82module_exit(dsi_exit);
diff --git a/drivers/video/tegra/host/gr2d/Makefile b/drivers/video/tegra/host/gr2d/Makefile
new file mode 100644
index 00000000000..a79a2101677
--- /dev/null
+++ b/drivers/video/tegra/host/gr2d/Makefile
@@ -0,0 +1,7 @@
1GCOV_PROFILE := y
2EXTRA_CFLAGS += -Idrivers/video/tegra/host
3
4nvhost-gr2d-objs = \
5 gr2d.o
6
7obj-$(CONFIG_TEGRA_GRHOST) += nvhost-gr2d.o
diff --git a/drivers/video/tegra/host/gr2d/gr2d.c b/drivers/video/tegra/host/gr2d/gr2d.c
new file mode 100644
index 00000000000..f88eb72e0a4
--- /dev/null
+++ b/drivers/video/tegra/host/gr2d/gr2d.c
@@ -0,0 +1,82 @@
1/*
2 * drivers/video/tegra/host/gr2d/gr2d.c
3 *
4 * Tegra Graphics 2D
5 *
6 * Copyright (c) 2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "dev.h"
22#include "bus_client.h"
23
24static int __devinit gr2d_probe(struct nvhost_device *dev)
25{
26 return nvhost_client_device_init(dev);
27}
28
29static int __exit gr2d_remove(struct nvhost_device *dev)
30{
31 /* Add clean-up */
32 return 0;
33}
34
35static int gr2d_suspend(struct nvhost_device *dev, pm_message_t state)
36{
37 return nvhost_client_device_suspend(dev);
38}
39
40static int gr2d_resume(struct nvhost_device *dev)
41{
42 dev_info(&dev->dev, "resuming\n");
43 return 0;
44}
45
46struct nvhost_device *gr2d_device;
47
48static struct nvhost_driver gr2d_driver = {
49 .probe = gr2d_probe,
50 .remove = __exit_p(gr2d_remove),
51#ifdef CONFIG_PM
52 .suspend = gr2d_suspend,
53 .resume = gr2d_resume,
54#endif
55 .driver = {
56 .owner = THIS_MODULE,
57 .name = "gr2d",
58 }
59};
60
61static int __init gr2d_init(void)
62{
63 int err;
64
65 gr2d_device = nvhost_get_device("gr2d");
66 if (!gr2d_device)
67 return -ENXIO;
68
69 err = nvhost_device_register(gr2d_device);
70 if (err)
71 return err;
72
73 return nvhost_driver_register(&gr2d_driver);
74}
75
76static void __exit gr2d_exit(void)
77{
78 nvhost_driver_unregister(&gr2d_driver);
79}
80
81module_init(gr2d_init);
82module_exit(gr2d_exit);
diff --git a/drivers/video/tegra/host/gr3d/Makefile b/drivers/video/tegra/host/gr3d/Makefile
new file mode 100644
index 00000000000..dfbd078ab42
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/Makefile
@@ -0,0 +1,10 @@
1GCOV_PROFILE := y
2EXTRA_CFLAGS += -Idrivers/video/tegra/host
3
4nvhost-gr3d-objs = \
5 gr3d.o \
6 gr3d_t20.o \
7 gr3d_t30.o \
8 scale3d.o
9
10obj-$(CONFIG_TEGRA_GRHOST) += nvhost-gr3d.o
diff --git a/drivers/video/tegra/host/gr3d/gr3d.c b/drivers/video/tegra/host/gr3d/gr3d.c
new file mode 100644
index 00000000000..f387d54e585
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d.c
@@ -0,0 +1,211 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d.c
3 *
4 * Tegra Graphics Host 3D
5 *
6 * Copyright (c) 2012 NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <mach/nvmap.h>
22#include <linux/slab.h>
23
24#include "t20/t20.h"
25#include "host1x/host1x_channel.h"
26#include "host1x/host1x_hardware.h"
27#include "host1x/host1x_syncpt.h"
28#include "nvhost_hwctx.h"
29#include "dev.h"
30#include "gr3d.h"
31#include "bus_client.h"
32
33#ifndef TEGRA_POWERGATE_3D1
34#define TEGRA_POWERGATE_3D1 -1
35#endif
36
37void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *p, u32 *ptr)
38{
39 /* set class to host */
40 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
41 NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
42 /* increment sync point base */
43 ptr[1] = nvhost_class_host_incr_syncpt_base(p->waitbase,
44 p->restore_incrs);
45 /* set class to 3D */
46 ptr[2] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
47 /* program PSEQ_QUAD_ID */
48 ptr[3] = nvhost_opcode_imm(AR3D_PSEQ_QUAD_ID, 0);
49}
50
51void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count)
52{
53 ptr[0] = nvhost_opcode_incr(start_reg, count);
54}
55
56void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg, u32 offset,
57 u32 data_reg, u32 count)
58{
59 ptr[0] = nvhost_opcode_imm(offset_reg, offset);
60 ptr[1] = nvhost_opcode_nonincr(data_reg, count);
61}
62
63void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *p, u32 *ptr)
64{
65 /* syncpt increment to track restore gather. */
66 ptr[0] = nvhost_opcode_imm_incr_syncpt(
67 NV_SYNCPT_OP_DONE, p->syncpt);
68}
69
70/*** ctx3d ***/
71
72struct host1x_hwctx *nvhost_3dctx_alloc_common(struct host1x_hwctx_handler *p,
73 struct nvhost_channel *ch, bool map_restore)
74{
75 struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
76 struct host1x_hwctx *ctx;
77
78 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
79 if (!ctx)
80 return NULL;
81 ctx->restore = nvmap_alloc(nvmap, p->restore_size * 4, 32,
82 map_restore ? NVMAP_HANDLE_WRITE_COMBINE
83 : NVMAP_HANDLE_UNCACHEABLE, 0);
84 if (IS_ERR_OR_NULL(ctx->restore))
85 goto fail;
86
87 if (map_restore) {
88 ctx->restore_virt = nvmap_mmap(ctx->restore);
89 if (!ctx->restore_virt)
90 goto fail;
91 } else
92 ctx->restore_virt = NULL;
93
94 kref_init(&ctx->hwctx.ref);
95 ctx->hwctx.h = &p->h;
96 ctx->hwctx.channel = ch;
97 ctx->hwctx.valid = false;
98 ctx->save_incrs = p->save_incrs;
99 ctx->save_thresh = p->save_thresh;
100 ctx->save_slots = p->save_slots;
101 ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
102 if (IS_ERR_VALUE(ctx->restore_phys))
103 goto fail;
104
105 ctx->restore_size = p->restore_size;
106 ctx->restore_incrs = p->restore_incrs;
107 return ctx;
108
109fail:
110 if (map_restore && ctx->restore_virt) {
111 nvmap_munmap(ctx->restore, ctx->restore_virt);
112 ctx->restore_virt = NULL;
113 }
114 nvmap_free(nvmap, ctx->restore);
115 ctx->restore = NULL;
116 kfree(ctx);
117 return NULL;
118}
119
120void nvhost_3dctx_get(struct nvhost_hwctx *ctx)
121{
122 kref_get(&ctx->ref);
123}
124
125void nvhost_3dctx_free(struct kref *ref)
126{
127 struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
128 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
129 struct nvmap_client *nvmap =
130 nvhost_get_host(nctx->channel->dev)->nvmap;
131
132 if (ctx->restore_virt) {
133 nvmap_munmap(ctx->restore, ctx->restore_virt);
134 ctx->restore_virt = NULL;
135 }
136 nvmap_unpin(nvmap, ctx->restore);
137 ctx->restore_phys = 0;
138 nvmap_free(nvmap, ctx->restore);
139 ctx->restore = NULL;
140 kfree(ctx);
141}
142
143void nvhost_3dctx_put(struct nvhost_hwctx *ctx)
144{
145 kref_put(&ctx->ref, nvhost_3dctx_free);
146}
147
148int nvhost_gr3d_prepare_power_off(struct nvhost_device *dev)
149{
150 return host1x_save_context(dev, NVSYNCPT_3D);
151}
152
153static int __devinit gr3d_probe(struct nvhost_device *dev)
154{
155 return nvhost_client_device_init(dev);
156}
157
158static int __exit gr3d_remove(struct nvhost_device *dev)
159{
160 /* Add clean-up */
161 return 0;
162}
163
164static int gr3d_suspend(struct nvhost_device *dev, pm_message_t state)
165{
166 return nvhost_client_device_suspend(dev);
167}
168
169static int gr3d_resume(struct nvhost_device *dev)
170{
171 dev_info(&dev->dev, "resuming\n");
172 return 0;
173}
174
175struct nvhost_device *gr3d_device;
176
177static struct nvhost_driver gr3d_driver = {
178 .probe = gr3d_probe,
179 .remove = __exit_p(gr3d_remove),
180#ifdef CONFIG_PM
181 .suspend = gr3d_suspend,
182 .resume = gr3d_resume,
183#endif
184 .driver = {
185 .owner = THIS_MODULE,
186 .name = "gr3d",
187 }
188};
189
190static int __init gr3d_init(void)
191{
192 int err;
193
194 gr3d_device = nvhost_get_device("gr3d");
195 if (!gr3d_device)
196 return -ENXIO;
197
198 err = nvhost_device_register(gr3d_device);
199 if (err)
200 return err;
201
202 return nvhost_driver_register(&gr3d_driver);
203}
204
205static void __exit gr3d_exit(void)
206{
207 nvhost_driver_unregister(&gr3d_driver);
208}
209
210module_init(gr3d_init);
211module_exit(gr3d_exit);
diff --git a/drivers/video/tegra/host/gr3d/gr3d.h b/drivers/video/tegra/host/gr3d/gr3d.h
new file mode 100644
index 00000000000..3855b237b70
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d.h
@@ -0,0 +1,54 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d.h
3 *
4 * Tegra Graphics Host 3D
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_GR3D_GR3D_H
22#define __NVHOST_GR3D_GR3D_H
23
24#include "host1x/host1x_hwctx.h"
25#include <linux/types.h>
26
27/* Registers of 3D unit */
28
29#define AR3D_PSEQ_QUAD_ID 0x545
30#define AR3D_DW_MEMORY_OUTPUT_ADDRESS 0x904
31#define AR3D_DW_MEMORY_OUTPUT_DATA 0x905
32#define AR3D_GSHIM_WRITE_MASK 0xb00
33#define AR3D_GSHIM_READ_SELECT 0xb01
34#define AR3D_GLOBAL_MEMORY_OUTPUT_READS 0xe40
35
36struct nvhost_hwctx;
37struct nvhost_channel;
38struct kref;
39
40/* Functions used commonly by all 3D context switch modules */
41void nvhost_3dctx_restore_begin(struct host1x_hwctx_handler *h, u32 *ptr);
42void nvhost_3dctx_restore_direct(u32 *ptr, u32 start_reg, u32 count);
43void nvhost_3dctx_restore_indirect(u32 *ptr, u32 offset_reg,
44 u32 offset, u32 data_reg, u32 count);
45void nvhost_3dctx_restore_end(struct host1x_hwctx_handler *h, u32 *ptr);
46struct host1x_hwctx *nvhost_3dctx_alloc_common(
47 struct host1x_hwctx_handler *p,
48 struct nvhost_channel *ch, bool map_restore);
49void nvhost_3dctx_get(struct nvhost_hwctx *ctx);
50void nvhost_3dctx_free(struct kref *ref);
51void nvhost_3dctx_put(struct nvhost_hwctx *ctx);
52int nvhost_gr3d_prepare_power_off(struct nvhost_device *dev);
53
54#endif
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.c b/drivers/video/tegra/host/gr3d/gr3d_t20.c
new file mode 100644
index 00000000000..3604142aaf2
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.c
@@ -0,0 +1,395 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d_t20.c
3 *
4 * Tegra Graphics Host 3D for Tegra2
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_hwctx.h"
22#include "dev.h"
23#include "host1x/host1x_channel.h"
24#include "host1x/host1x_hardware.h"
25#include "host1x/host1x_syncpt.h"
26#include "gr3d.h"
27
28#include <linux/slab.h>
29
30static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
31 HWCTX_REGINFO(0xe00, 4, DIRECT),
32 HWCTX_REGINFO(0xe05, 30, DIRECT),
33 HWCTX_REGINFO(0xe25, 2, DIRECT),
34 HWCTX_REGINFO(0xe28, 2, DIRECT),
35 HWCTX_REGINFO(0x001, 2, DIRECT),
36 HWCTX_REGINFO(0x00c, 10, DIRECT),
37 HWCTX_REGINFO(0x100, 34, DIRECT),
38 HWCTX_REGINFO(0x124, 2, DIRECT),
39 HWCTX_REGINFO(0x200, 5, DIRECT),
40 HWCTX_REGINFO(0x205, 1024, INDIRECT),
41 HWCTX_REGINFO(0x207, 1024, INDIRECT),
42 HWCTX_REGINFO(0x209, 1, DIRECT),
43 HWCTX_REGINFO(0x300, 64, DIRECT),
44 HWCTX_REGINFO(0x343, 25, DIRECT),
45 HWCTX_REGINFO(0x363, 2, DIRECT),
46 HWCTX_REGINFO(0x400, 16, DIRECT),
47 HWCTX_REGINFO(0x411, 1, DIRECT),
48 HWCTX_REGINFO(0x500, 4, DIRECT),
49 HWCTX_REGINFO(0x520, 32, DIRECT),
50 HWCTX_REGINFO(0x540, 64, INDIRECT),
51 HWCTX_REGINFO(0x600, 16, INDIRECT_4X),
52 HWCTX_REGINFO(0x603, 128, INDIRECT),
53 HWCTX_REGINFO(0x608, 4, DIRECT),
54 HWCTX_REGINFO(0x60e, 1, DIRECT),
55 HWCTX_REGINFO(0x700, 64, INDIRECT),
56 HWCTX_REGINFO(0x710, 50, DIRECT),
57 HWCTX_REGINFO(0x800, 16, INDIRECT_4X),
58 HWCTX_REGINFO(0x803, 512, INDIRECT),
59 HWCTX_REGINFO(0x805, 64, INDIRECT),
60 HWCTX_REGINFO(0x820, 32, DIRECT),
61 HWCTX_REGINFO(0x900, 64, INDIRECT),
62 HWCTX_REGINFO(0x902, 2, DIRECT),
63 HWCTX_REGINFO(0xa02, 10, DIRECT),
64 HWCTX_REGINFO(0xe04, 1, DIRECT),
65 HWCTX_REGINFO(0xe2a, 1, DIRECT),
66};
67
68/* the same context save command sequence is used for all contexts. */
69#define SAVE_BEGIN_V0_SIZE 5
70#define SAVE_DIRECT_V0_SIZE 3
71#define SAVE_INDIRECT_V0_SIZE 5
72#define SAVE_END_V0_SIZE 5
73#define SAVE_INCRS 3
74#define SAVE_THRESH_OFFSET 1
75#define RESTORE_BEGIN_SIZE 4
76#define RESTORE_DIRECT_SIZE 1
77#define RESTORE_INDIRECT_SIZE 2
78#define RESTORE_END_SIZE 1
79
80struct save_info {
81 u32 *ptr;
82 unsigned int save_count;
83 unsigned int restore_count;
84 unsigned int save_incrs;
85 unsigned int restore_incrs;
86};
87
88static u32 *setup_restore_regs_v0(u32 *ptr,
89 const struct hwctx_reginfo *regs,
90 unsigned int nr_regs)
91{
92 const struct hwctx_reginfo *rend = regs + nr_regs;
93
94 for ( ; regs != rend; ++regs) {
95 u32 offset = regs->offset;
96 u32 count = regs->count;
97 u32 indoff = offset + 1;
98 switch (regs->type) {
99 case HWCTX_REGINFO_DIRECT:
100 nvhost_3dctx_restore_direct(ptr, offset, count);
101 ptr += RESTORE_DIRECT_SIZE;
102 break;
103 case HWCTX_REGINFO_INDIRECT_4X:
104 ++indoff;
105 /* fall through */
106 case HWCTX_REGINFO_INDIRECT:
107 nvhost_3dctx_restore_indirect(ptr,
108 offset, 0, indoff, count);
109 ptr += RESTORE_INDIRECT_SIZE;
110 break;
111 }
112 ptr += count;
113 }
114 return ptr;
115}
116
117static void setup_restore_v0(struct host1x_hwctx_handler *h, u32 *ptr)
118{
119 nvhost_3dctx_restore_begin(h, ptr);
120 ptr += RESTORE_BEGIN_SIZE;
121
122 ptr = setup_restore_regs_v0(ptr,
123 ctxsave_regs_3d_global,
124 ARRAY_SIZE(ctxsave_regs_3d_global));
125
126 nvhost_3dctx_restore_end(h, ptr);
127
128 wmb();
129}
130
131/*** v0 saver ***/
132
133static void save_push_v0(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
134{
135 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
136 struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
137
138 nvhost_cdma_push_gather(cdma,
139 (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
140 (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
141 nvhost_opcode_gather(p->save_size),
142 p->save_phys);
143}
144
145static void __init save_begin_v0(struct host1x_hwctx_handler *h, u32 *ptr)
146{
147 /* 3d: when done, increment syncpt to base+1 */
148 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
149 ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
150 h->syncpt); /* incr 1 */
151 /* host: wait for syncpt base+1 */
152 ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
153 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
154 ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt,
155 h->waitbase, 1);
156 /* host: signal context read thread to start reading */
157 ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
158 h->syncpt); /* incr 2 */
159}
160
161static void __init save_direct_v0(u32 *ptr, u32 start_reg, u32 count)
162{
163 ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1);
164 ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
165 start_reg, true);
166 ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
167}
168
169static void __init save_indirect_v0(u32 *ptr, u32 offset_reg, u32 offset,
170 u32 data_reg, u32 count)
171{
172 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
173 offset_reg, 1);
174 ptr[1] = offset;
175 ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
176 NV_CLASS_HOST_INDOFF, 1);
177 ptr[3] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
178 data_reg, false);
179 ptr[4] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
180}
181
182static void __init save_end_v0(struct host1x_hwctx_handler *h, u32 *ptr)
183{
184 /* Wait for context read service to finish (cpu incr 3) */
185 ptr[0] = nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
186 ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt,
187 h->waitbase, h->save_incrs);
188 /* Advance syncpoint base */
189 ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
190 ptr[3] = nvhost_class_host_incr_syncpt_base(NVWAITBASE_3D,
191 h->save_incrs);
192 /* set class back to the unit */
193 ptr[4] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
194}
195
196static u32 *save_regs_v0(u32 *ptr, unsigned int *pending,
197 void __iomem *chan_regs,
198 const struct hwctx_reginfo *regs,
199 unsigned int nr_regs)
200{
201 const struct hwctx_reginfo *rend = regs + nr_regs;
202 int drain_result = 0;
203
204 for ( ; regs != rend; ++regs) {
205 u32 count = regs->count;
206 switch (regs->type) {
207 case HWCTX_REGINFO_DIRECT:
208 ptr += RESTORE_DIRECT_SIZE;
209 break;
210 case HWCTX_REGINFO_INDIRECT:
211 case HWCTX_REGINFO_INDIRECT_4X:
212 ptr += RESTORE_INDIRECT_SIZE;
213 break;
214 }
215 drain_result = host1x_drain_read_fifo(chan_regs,
216 ptr, count, pending);
217 BUG_ON(drain_result < 0);
218 ptr += count;
219 }
220 return ptr;
221}
222
223/*** save ***/
224
225static void __init setup_save_regs(struct save_info *info,
226 const struct hwctx_reginfo *regs,
227 unsigned int nr_regs)
228{
229 const struct hwctx_reginfo *rend = regs + nr_regs;
230 u32 *ptr = info->ptr;
231 unsigned int save_count = info->save_count;
232 unsigned int restore_count = info->restore_count;
233
234 for ( ; regs != rend; ++regs) {
235 u32 offset = regs->offset;
236 u32 count = regs->count;
237 u32 indoff = offset + 1;
238 switch (regs->type) {
239 case HWCTX_REGINFO_DIRECT:
240 if (ptr) {
241 save_direct_v0(ptr, offset, count);
242 ptr += SAVE_DIRECT_V0_SIZE;
243 }
244 save_count += SAVE_DIRECT_V0_SIZE;
245 restore_count += RESTORE_DIRECT_SIZE;
246 break;
247 case HWCTX_REGINFO_INDIRECT_4X:
248 ++indoff;
249 /* fall through */
250 case HWCTX_REGINFO_INDIRECT:
251 if (ptr) {
252 save_indirect_v0(ptr, offset, 0,
253 indoff, count);
254 ptr += SAVE_INDIRECT_V0_SIZE;
255 }
256 save_count += SAVE_INDIRECT_V0_SIZE;
257 restore_count += RESTORE_INDIRECT_SIZE;
258 break;
259 }
260 if (ptr) {
261 /* SAVE cases only: reserve room for incoming data */
262 u32 k = 0;
263 /*
264 * Create a signature pattern for indirect data (which
265 * will be overwritten by true incoming data) for
266 * better deducing where we are in a long command
267 * sequence, when given only a FIFO snapshot for debug
268 * purposes.
269 */
270 for (k = 0; k < count; k++)
271 *(ptr + k) = 0xd000d000 | (offset << 16) | k;
272 ptr += count;
273 }
274 save_count += count;
275 restore_count += count;
276 }
277
278 info->ptr = ptr;
279 info->save_count = save_count;
280 info->restore_count = restore_count;
281}
282
283static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
284{
285 struct save_info info = {
286 ptr,
287 SAVE_BEGIN_V0_SIZE,
288 RESTORE_BEGIN_SIZE,
289 SAVE_INCRS,
290 1
291 };
292
293 if (info.ptr) {
294 save_begin_v0(h, info.ptr);
295 info.ptr += SAVE_BEGIN_V0_SIZE;
296 }
297
298 /* save regs */
299 setup_save_regs(&info,
300 ctxsave_regs_3d_global,
301 ARRAY_SIZE(ctxsave_regs_3d_global));
302
303 if (info.ptr) {
304 save_end_v0(h, info.ptr);
305 info.ptr += SAVE_END_V0_SIZE;
306 }
307
308 wmb();
309
310 h->save_size = info.save_count + SAVE_END_V0_SIZE;
311 h->restore_size = info.restore_count + RESTORE_END_SIZE;
312 h->save_incrs = info.save_incrs;
313 h->save_thresh = h->save_incrs - SAVE_THRESH_OFFSET;
314 h->restore_incrs = info.restore_incrs;
315}
316
317
318
319/*** ctx3d ***/
320
321static struct nvhost_hwctx *ctx3d_alloc_v0(struct nvhost_hwctx_handler *h,
322 struct nvhost_channel *ch)
323{
324 struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
325 struct host1x_hwctx *ctx =
326 nvhost_3dctx_alloc_common(p, ch, true);
327 if (ctx) {
328 setup_restore_v0(p, ctx->restore_virt);
329 return &ctx->hwctx;
330 } else
331 return NULL;
332}
333
334static void ctx3d_save_service(struct nvhost_hwctx *nctx)
335{
336 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
337
338 u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
339 unsigned int pending = 0;
340
341 ptr = save_regs_v0(ptr, &pending, nctx->channel->aperture,
342 ctxsave_regs_3d_global,
343 ARRAY_SIZE(ctxsave_regs_3d_global));
344
345 wmb();
346 nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
347 host1x_hwctx_handler(ctx)->syncpt);
348}
349
350struct nvhost_hwctx_handler * __init nvhost_gr3d_t20_ctxhandler_init(
351 u32 syncpt, u32 waitbase,
352 struct nvhost_channel *ch)
353{
354 struct nvmap_client *nvmap;
355 u32 *save_ptr;
356 struct host1x_hwctx_handler *p;
357
358 p = kmalloc(sizeof(*p), GFP_KERNEL);
359 if (!p)
360 return NULL;
361 nvmap = nvhost_get_host(ch->dev)->nvmap;
362
363 p->syncpt = syncpt;
364 p->waitbase = waitbase;
365
366 setup_save(p, NULL);
367
368 p->save_buf = nvmap_alloc(nvmap, p->save_size * sizeof(u32), 32,
369 NVMAP_HANDLE_WRITE_COMBINE, 0);
370 if (IS_ERR(p->save_buf)) {
371 p->save_buf = NULL;
372 return NULL;
373 }
374
375 p->save_slots = 1;
376
377 save_ptr = nvmap_mmap(p->save_buf);
378 if (!save_ptr) {
379 nvmap_free(nvmap, p->save_buf);
380 p->save_buf = NULL;
381 return NULL;
382 }
383
384 p->save_phys = nvmap_pin(nvmap, p->save_buf);
385
386 setup_save(p, save_ptr);
387
388 p->h.alloc = ctx3d_alloc_v0;
389 p->h.save_push = save_push_v0;
390 p->h.save_service = ctx3d_save_service;
391 p->h.get = nvhost_3dctx_get;
392 p->h.put = nvhost_3dctx_put;
393
394 return &p->h;
395}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t20.h b/drivers/video/tegra/host/gr3d/gr3d_t20.h
new file mode 100644
index 00000000000..5fe6d50d0c3
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t20.h
@@ -0,0 +1,30 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d_t20.h
3 *
4 * Tegra Graphics Host 3D for Tegra2
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_GR3D_GR3D_T20_H
22#define __NVHOST_GR3D_GR3D_T20_H
23
24struct nvhost_hwctx_handler;
25
26struct nvhost_hwctx_handler *nvhost_gr3d_t20_ctxhandler_init(
27 u32 syncpt, u32 waitbase,
28 struct nvhost_channel *ch);
29
30#endif
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.c b/drivers/video/tegra/host/gr3d/gr3d_t30.c
new file mode 100644
index 00000000000..e7329e50e3d
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.c
@@ -0,0 +1,435 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d_t30.c
3 *
4 * Tegra Graphics Host 3D for Tegra3
5 *
6 * Copyright (c) 2011-2012 NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_hwctx.h"
22#include "dev.h"
23#include "host1x/host1x_hardware.h"
24#include "host1x/host1x_syncpt.h"
25#include "gr3d.h"
26
27#include <mach/gpufuse.h>
28#include <mach/hardware.h>
29#include <linux/slab.h>
30
31/* 99 > 2, which makes kernel panic if register set is incorrect */
32static int register_sets = 99;
33
34static const struct hwctx_reginfo ctxsave_regs_3d_global[] = {
35 HWCTX_REGINFO(0xe00, 4, DIRECT),
36 HWCTX_REGINFO(0xe05, 30, DIRECT),
37 HWCTX_REGINFO(0xe25, 2, DIRECT),
38 HWCTX_REGINFO(0xe28, 2, DIRECT),
39 HWCTX_REGINFO(0xe30, 16, DIRECT),
40 HWCTX_REGINFO(0x001, 2, DIRECT),
41 HWCTX_REGINFO(0x00c, 10, DIRECT),
42 HWCTX_REGINFO(0x100, 34, DIRECT),
43 HWCTX_REGINFO(0x124, 2, DIRECT),
44 HWCTX_REGINFO(0x200, 5, DIRECT),
45 HWCTX_REGINFO(0x205, 1024, INDIRECT),
46 HWCTX_REGINFO(0x207, 1024, INDIRECT),
47 HWCTX_REGINFO(0x209, 1, DIRECT),
48 HWCTX_REGINFO(0x300, 64, DIRECT),
49 HWCTX_REGINFO(0x343, 25, DIRECT),
50 HWCTX_REGINFO(0x363, 2, DIRECT),
51 HWCTX_REGINFO(0x400, 16, DIRECT),
52 HWCTX_REGINFO(0x411, 1, DIRECT),
53 HWCTX_REGINFO(0x412, 1, DIRECT),
54 HWCTX_REGINFO(0x500, 4, DIRECT),
55 HWCTX_REGINFO(0x520, 32, DIRECT),
56 HWCTX_REGINFO(0x540, 64, INDIRECT),
57 HWCTX_REGINFO(0x600, 16, INDIRECT_4X),
58 HWCTX_REGINFO(0x603, 128, INDIRECT),
59 HWCTX_REGINFO(0x608, 4, DIRECT),
60 HWCTX_REGINFO(0x60e, 1, DIRECT),
61 HWCTX_REGINFO(0x700, 64, INDIRECT),
62 HWCTX_REGINFO(0x710, 50, DIRECT),
63 HWCTX_REGINFO(0x750, 16, DIRECT),
64 HWCTX_REGINFO(0x800, 16, INDIRECT_4X),
65 HWCTX_REGINFO(0x803, 512, INDIRECT),
66 HWCTX_REGINFO(0x805, 64, INDIRECT),
67 HWCTX_REGINFO(0x820, 32, DIRECT),
68 HWCTX_REGINFO(0x900, 64, INDIRECT),
69 HWCTX_REGINFO(0x902, 2, DIRECT),
70 HWCTX_REGINFO(0x90a, 1, DIRECT),
71 HWCTX_REGINFO(0xa02, 10, DIRECT),
72 HWCTX_REGINFO(0xb04, 1, DIRECT),
73 HWCTX_REGINFO(0xb06, 13, DIRECT),
74 HWCTX_REGINFO(0xe42, 2, DIRECT), /* HW bug workaround */
75};
76
77static const struct hwctx_reginfo ctxsave_regs_3d_perset[] = {
78 HWCTX_REGINFO(0xe04, 1, DIRECT),
79 HWCTX_REGINFO(0xe2a, 1, DIRECT),
80 HWCTX_REGINFO(0x413, 1, DIRECT),
81 HWCTX_REGINFO(0x90b, 1, DIRECT),
82 HWCTX_REGINFO(0xe41, 1, DIRECT),
83};
84
85static unsigned int restore_set1_offset;
86
87#define SAVE_BEGIN_V1_SIZE (1 + RESTORE_BEGIN_SIZE)
88#define SAVE_DIRECT_V1_SIZE (4 + RESTORE_DIRECT_SIZE)
89#define SAVE_INDIRECT_V1_SIZE (6 + RESTORE_INDIRECT_SIZE)
90#define SAVE_END_V1_SIZE (9 + RESTORE_END_SIZE)
91#define SAVE_INCRS 3
92#define SAVE_THRESH_OFFSET 0
93#define RESTORE_BEGIN_SIZE 4
94#define RESTORE_DIRECT_SIZE 1
95#define RESTORE_INDIRECT_SIZE 2
96#define RESTORE_END_SIZE 1
97
98struct save_info {
99 u32 *ptr;
100 unsigned int save_count;
101 unsigned int restore_count;
102 unsigned int save_incrs;
103 unsigned int restore_incrs;
104};
105
106/*** v1 saver ***/
107
108static void save_push_v1(struct nvhost_hwctx *nctx, struct nvhost_cdma *cdma)
109{
110 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
111 struct host1x_hwctx_handler *p = host1x_hwctx_handler(ctx);
112
113 /* wait for 3d idle */
114 nvhost_cdma_push(cdma,
115 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
116 nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
117 p->syncpt));
118 nvhost_cdma_push(cdma,
119 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
120 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
121 nvhost_class_host_wait_syncpt_base(p->syncpt,
122 p->waitbase, 1));
123 /* back to 3d */
124 nvhost_cdma_push(cdma,
125 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
126 NVHOST_OPCODE_NOOP);
127 /* set register set 0 and 1 register read memory output addresses,
128 and send their reads to memory */
129 if (register_sets == 2) {
130 nvhost_cdma_push(cdma,
131 nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 2),
132 nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS,
133 1));
134 nvhost_cdma_push(cdma,
135 nvhost_opcode_nonincr(0x904, 1),
136 ctx->restore_phys + restore_set1_offset * 4);
137 }
138 nvhost_cdma_push(cdma,
139 nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK, 1),
140 nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 1));
141 nvhost_cdma_push(cdma,
142 nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_ADDRESS, 1),
143 ctx->restore_phys);
144 /* gather the save buffer */
145 nvhost_cdma_push_gather(cdma,
146 (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
147 (void *)NVHOST_CDMA_PUSH_GATHER_CTXSAVE,
148 nvhost_opcode_gather(p->save_size),
149 p->save_phys);
150}
151
152static void __init save_begin_v1(struct host1x_hwctx_handler *p, u32 *ptr)
153{
154 ptr[0] = nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_DATA,
155 RESTORE_BEGIN_SIZE);
156 nvhost_3dctx_restore_begin(p, ptr + 1);
157 ptr += RESTORE_BEGIN_SIZE;
158}
159
160static void __init save_direct_v1(u32 *ptr, u32 start_reg, u32 count)
161{
162 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
163 AR3D_DW_MEMORY_OUTPUT_DATA, 1);
164 nvhost_3dctx_restore_direct(ptr + 1, start_reg, count);
165 ptr += RESTORE_DIRECT_SIZE;
166 ptr[1] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
167 NV_CLASS_HOST_INDOFF, 1);
168 ptr[2] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
169 start_reg, true);
170 /* TODO could do this in the setclass if count < 6 */
171 ptr[3] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
172}
173
174static void __init save_indirect_v1(u32 *ptr, u32 offset_reg, u32 offset,
175 u32 data_reg, u32 count)
176{
177 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
178 ptr[1] = nvhost_opcode_nonincr(AR3D_DW_MEMORY_OUTPUT_DATA,
179 RESTORE_INDIRECT_SIZE);
180 nvhost_3dctx_restore_indirect(ptr + 2, offset_reg, offset, data_reg,
181 count);
182 ptr += RESTORE_INDIRECT_SIZE;
183 ptr[2] = nvhost_opcode_imm(offset_reg, offset);
184 ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
185 NV_CLASS_HOST_INDOFF, 1);
186 ptr[4] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
187 data_reg, false);
188 ptr[5] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
189}
190
191static void __init save_end_v1(struct host1x_hwctx_handler *p, u32 *ptr)
192{
193 /* write end of restore buffer */
194 ptr[0] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID,
195 AR3D_DW_MEMORY_OUTPUT_DATA, 1);
196 nvhost_3dctx_restore_end(p, ptr + 1);
197 ptr += RESTORE_END_SIZE;
198 /* reset to dual reg if necessary */
199 ptr[1] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
200 (1 << register_sets) - 1);
201 /* op_done syncpt incr to flush FDC */
202 ptr[2] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, p->syncpt);
203 /* host wait for that syncpt incr, and advance the wait base */
204 ptr[3] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
205 NV_CLASS_HOST_WAIT_SYNCPT_BASE,
206 nvhost_mask2(
207 NV_CLASS_HOST_WAIT_SYNCPT_BASE,
208 NV_CLASS_HOST_INCR_SYNCPT_BASE));
209 ptr[4] = nvhost_class_host_wait_syncpt_base(p->syncpt,
210 p->waitbase, p->save_incrs - 1);
211 ptr[5] = nvhost_class_host_incr_syncpt_base(p->waitbase,
212 p->save_incrs);
213 /* set class back to 3d */
214 ptr[6] = nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0);
215 /* send reg reads back to host */
216 ptr[7] = nvhost_opcode_imm(AR3D_GLOBAL_MEMORY_OUTPUT_READS, 0);
217 /* final syncpt increment to release waiters */
218 ptr[8] = nvhost_opcode_imm(0, p->syncpt);
219}
220
221/*** save ***/
222
223
224
225static void __init setup_save_regs(struct save_info *info,
226 const struct hwctx_reginfo *regs,
227 unsigned int nr_regs)
228{
229 const struct hwctx_reginfo *rend = regs + nr_regs;
230 u32 *ptr = info->ptr;
231 unsigned int save_count = info->save_count;
232 unsigned int restore_count = info->restore_count;
233
234 for ( ; regs != rend; ++regs) {
235 u32 offset = regs->offset;
236 u32 count = regs->count;
237 u32 indoff = offset + 1;
238 switch (regs->type) {
239 case HWCTX_REGINFO_DIRECT:
240 if (ptr) {
241 save_direct_v1(ptr, offset, count);
242 ptr += SAVE_DIRECT_V1_SIZE;
243 }
244 save_count += SAVE_DIRECT_V1_SIZE;
245 restore_count += RESTORE_DIRECT_SIZE;
246 break;
247 case HWCTX_REGINFO_INDIRECT_4X:
248 ++indoff;
249 /* fall through */
250 case HWCTX_REGINFO_INDIRECT:
251 if (ptr) {
252 save_indirect_v1(ptr, offset, 0,
253 indoff, count);
254 ptr += SAVE_INDIRECT_V1_SIZE;
255 }
256 save_count += SAVE_INDIRECT_V1_SIZE;
257 restore_count += RESTORE_INDIRECT_SIZE;
258 break;
259 }
260 if (ptr) {
261 /* SAVE cases only: reserve room for incoming data */
262 u32 k = 0;
263 /*
264 * Create a signature pattern for indirect data (which
265 * will be overwritten by true incoming data) for
266 * better deducing where we are in a long command
267 * sequence, when given only a FIFO snapshot for debug
268 * purposes.
269 */
270 for (k = 0; k < count; k++)
271 *(ptr + k) = 0xd000d000 | (offset << 16) | k;
272 ptr += count;
273 }
274 save_count += count;
275 restore_count += count;
276 }
277
278 info->ptr = ptr;
279 info->save_count = save_count;
280 info->restore_count = restore_count;
281}
282
283static void __init switch_gpu(struct save_info *info,
284 unsigned int save_src_set,
285 u32 save_dest_sets,
286 u32 restore_dest_sets)
287{
288 if (info->ptr) {
289 info->ptr[0] = nvhost_opcode_setclass(
290 NV_GRAPHICS_3D_CLASS_ID,
291 AR3D_DW_MEMORY_OUTPUT_DATA, 1);
292 info->ptr[1] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
293 restore_dest_sets);
294 info->ptr[2] = nvhost_opcode_imm(AR3D_GSHIM_WRITE_MASK,
295 save_dest_sets);
296 info->ptr[3] = nvhost_opcode_imm(AR3D_GSHIM_READ_SELECT,
297 save_src_set);
298 info->ptr += 4;
299 }
300 info->save_count += 4;
301 info->restore_count += 1;
302}
303
304static void __init setup_save(struct host1x_hwctx_handler *p, u32 *ptr)
305{
306 struct save_info info = {
307 ptr,
308 SAVE_BEGIN_V1_SIZE,
309 RESTORE_BEGIN_SIZE,
310 SAVE_INCRS,
311 1
312 };
313 int save_end_size = SAVE_END_V1_SIZE;
314
315 BUG_ON(register_sets > 2);
316
317 if (info.ptr) {
318 save_begin_v1(p, info.ptr);
319 info.ptr += SAVE_BEGIN_V1_SIZE;
320 }
321
322 /* read from set0, write cmds through set0, restore to set0 and 1 */
323 if (register_sets == 2)
324 switch_gpu(&info, 0, 1, 3);
325
326 /* save regs that are common to both sets */
327 setup_save_regs(&info,
328 ctxsave_regs_3d_global,
329 ARRAY_SIZE(ctxsave_regs_3d_global));
330
331 /* read from set 0, write cmds through set0, restore to set0 */
332 if (register_sets == 2)
333 switch_gpu(&info, 0, 1, 1);
334
335 /* save set 0 specific regs */
336 setup_save_regs(&info,
337 ctxsave_regs_3d_perset,
338 ARRAY_SIZE(ctxsave_regs_3d_perset));
339
340 if (register_sets == 2) {
341 /* read from set1, write cmds through set1, restore to set1 */
342 switch_gpu(&info, 1, 2, 2);
343 /* note offset at which set 1 restore starts */
344 restore_set1_offset = info.restore_count;
345 /* save set 1 specific regs */
346 setup_save_regs(&info,
347 ctxsave_regs_3d_perset,
348 ARRAY_SIZE(ctxsave_regs_3d_perset));
349 }
350
351 /* read from set0, write cmds through set1, restore to set0 and 1 */
352 if (register_sets == 2)
353 switch_gpu(&info, 0, 2, 3);
354
355 if (info.ptr) {
356 save_end_v1(p, info.ptr);
357 info.ptr += SAVE_END_V1_SIZE;
358 }
359
360 wmb();
361
362 p->save_size = info.save_count + save_end_size;
363 p->restore_size = info.restore_count + RESTORE_END_SIZE;
364 p->save_incrs = info.save_incrs;
365 p->save_thresh = p->save_incrs - SAVE_THRESH_OFFSET;
366 p->restore_incrs = info.restore_incrs;
367}
368
369
370/*** ctx3d ***/
371
372static struct nvhost_hwctx *ctx3d_alloc_v1(struct nvhost_hwctx_handler *h,
373 struct nvhost_channel *ch)
374{
375 struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
376 struct host1x_hwctx *ctx = nvhost_3dctx_alloc_common(p, ch, false);
377
378 if (ctx)
379 return &ctx->hwctx;
380 else
381 return NULL;
382}
383
384struct nvhost_hwctx_handler *__init nvhost_gr3d_t30_ctxhandler_init(
385 u32 syncpt, u32 waitbase,
386 struct nvhost_channel *ch)
387{
388 struct nvmap_client *nvmap;
389 u32 *save_ptr;
390 struct host1x_hwctx_handler *p;
391
392 p = kmalloc(sizeof(*p), GFP_KERNEL);
393 if (!p)
394 return NULL;
395
396 nvmap = nvhost_get_host(ch->dev)->nvmap;
397
398 register_sets = tegra_gpu_register_sets();
399 BUG_ON(register_sets == 0 || register_sets > 2);
400
401 p->syncpt = syncpt;
402 p->waitbase = waitbase;
403
404 setup_save(p, NULL);
405
406 p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
407 NVMAP_HANDLE_WRITE_COMBINE, 0);
408 if (IS_ERR(p->save_buf)) {
409 p->save_buf = NULL;
410 return NULL;
411 }
412
413 p->save_slots = 6;
414 if (register_sets == 2)
415 p->save_slots += 2;
416
417 save_ptr = nvmap_mmap(p->save_buf);
418 if (!save_ptr) {
419 nvmap_free(nvmap, p->save_buf);
420 p->save_buf = NULL;
421 return NULL;
422 }
423
424 p->save_phys = nvmap_pin(nvmap, p->save_buf);
425
426 setup_save(p, save_ptr);
427
428 p->h.alloc = ctx3d_alloc_v1;
429 p->h.save_push = save_push_v1;
430 p->h.save_service = NULL;
431 p->h.get = nvhost_3dctx_get;
432 p->h.put = nvhost_3dctx_put;
433
434 return &p->h;
435}
diff --git a/drivers/video/tegra/host/gr3d/gr3d_t30.h b/drivers/video/tegra/host/gr3d/gr3d_t30.h
new file mode 100644
index 00000000000..d1b787e14b4
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/gr3d_t30.h
@@ -0,0 +1,30 @@
1/*
2 * drivers/video/tegra/host/gr3d/gr3d_t30.h
3 *
4 * Tegra Graphics Host 3D for Tegra3
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_GR3D_GR3D_T30_H
22#define __NVHOST_GR3D_GR3D_T30_H
23
24struct nvhost_hwctx_handler;
25
26struct nvhost_hwctx_handler *nvhost_gr3d_t30_ctxhandler_init(
27 u32 syncpt, u32 waitbase,
28 struct nvhost_channel *ch);
29
30#endif
diff --git a/drivers/video/tegra/host/gr3d/scale3d.c b/drivers/video/tegra/host/gr3d/scale3d.c
new file mode 100644
index 00000000000..8a267a127ea
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/scale3d.c
@@ -0,0 +1,661 @@
1/*
2 * drivers/video/tegra/host/t20/scale3d.c
3 *
4 * Tegra Graphics Host 3D clock scaling
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/*
22 * 3d clock scaling
23 *
24 * module3d_notify_busy() is called upon submit, module3d_notify_idle() is
25 * called when all outstanding submits are completed. Idle times are measured
26 * over a fixed time period (scale3d.p_period). If the 3d module idle time
27 * percentage goes over the limit (set in scale3d.p_idle_max), 3d clocks are
28 * scaled down. If the percentage goes under the minimum limit (set in
29 * scale3d.p_idle_min), 3d clocks are scaled up. An additional test is made
30 * over the time frame given in scale3d.p_fast_response for clocking up
31 * quickly in response to load peaks.
32 *
33 * 3d.emc clock is scaled proportionately to 3d clock, with a quadratic-
34 * bezier-like factor added to pull 3d.emc rate a bit lower.
35 */
36
37#include <linux/debugfs.h>
38#include <linux/types.h>
39#include <linux/clk.h>
40#include <mach/clk.h>
41#include <mach/hardware.h>
42#include "scale3d.h"
43#include "dev.h"
44
45static int scale3d_is_enabled(void);
46static void scale3d_enable(int enable);
47
48#define POW2(x) ((x) * (x))
49
50/*
51 * debugfs parameters to control 3d clock scaling test
52 *
53 * period - time period for clock rate evaluation
54 * fast_response - time period for evaluation of 'busy' spikes
55 * idle_min - if less than [idle_min] percent idle over [fast_response]
56 * microseconds, clock up.
57 * idle_max - if over [idle_max] percent idle over [period] microseconds,
58 * clock down.
59 * max_scale - limits rate changes to no less than (100 - max_scale)% or
60 * (100 + 2 * max_scale)% of current clock rate
61 * verbosity - set above 5 for debug printouts
62 */
63
64struct scale3d_info_rec {
65 struct mutex lock; /* lock for timestamps etc */
66 int enable;
67 int init;
68 ktime_t idle_frame;
69 ktime_t fast_frame;
70 ktime_t last_idle;
71 ktime_t last_short_term_idle;
72 int is_idle;
73 ktime_t last_tweak;
74 ktime_t last_down;
75 int fast_up_count;
76 int slow_down_count;
77 int is_scaled;
78 int fast_responses;
79 unsigned long idle_total;
80 unsigned long idle_short_term_total;
81 unsigned long max_rate_3d;
82 long emc_slope;
83 long emc_offset;
84 long emc_dip_slope;
85 long emc_dip_offset;
86 long emc_xmid;
87 unsigned long min_rate_3d;
88 struct work_struct work;
89 struct delayed_work idle_timer;
90 unsigned int scale;
91 unsigned int p_period;
92 unsigned int period;
93 unsigned int p_idle_min;
94 unsigned int idle_min;
95 unsigned int p_idle_max;
96 unsigned int idle_max;
97 unsigned int p_fast_response;
98 unsigned int fast_response;
99 unsigned int p_adjust;
100 unsigned int p_scale_emc;
101 unsigned int p_emc_dip;
102 unsigned int p_verbosity;
103 struct clk *clk_3d;
104 struct clk *clk_3d2;
105 struct clk *clk_3d_emc;
106};
107
108static struct scale3d_info_rec scale3d;
109
110static void scale3d_clocks(unsigned long percent)
111{
112 unsigned long hz, curr;
113
114 if (!tegra_is_clk_enabled(scale3d.clk_3d))
115 return;
116
117 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
118 if (!tegra_is_clk_enabled(scale3d.clk_3d2))
119 return;
120
121 curr = clk_get_rate(scale3d.clk_3d);
122 hz = percent * (curr / 100);
123
124 if (!(hz >= scale3d.max_rate_3d && curr == scale3d.max_rate_3d)) {
125 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
126 clk_set_rate(scale3d.clk_3d2, 0);
127 clk_set_rate(scale3d.clk_3d, hz);
128
129 if (scale3d.p_scale_emc) {
130 long after = (long) clk_get_rate(scale3d.clk_3d);
131 hz = after * scale3d.emc_slope + scale3d.emc_offset;
132 if (scale3d.p_emc_dip)
133 hz -=
134 (scale3d.emc_dip_slope *
135 POW2(after / 1000 - scale3d.emc_xmid) +
136 scale3d.emc_dip_offset);
137 clk_set_rate(scale3d.clk_3d_emc, hz);
138 }
139 }
140}
141
142static void scale3d_clocks_handler(struct work_struct *work)
143{
144 unsigned int scale;
145
146 mutex_lock(&scale3d.lock);
147 scale = scale3d.scale;
148 mutex_unlock(&scale3d.lock);
149
150 if (scale != 0)
151 scale3d_clocks(scale);
152}
153
154void nvhost_scale3d_suspend(struct nvhost_device *dev)
155{
156 if (!scale3d.enable)
157 return;
158
159 cancel_work_sync(&scale3d.work);
160 cancel_delayed_work(&scale3d.idle_timer);
161}
162
163/* set 3d clocks to max */
164static void reset_3d_clocks(void)
165{
166 if (clk_get_rate(scale3d.clk_3d) != scale3d.max_rate_3d) {
167 clk_set_rate(scale3d.clk_3d, scale3d.max_rate_3d);
168 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3)
169 clk_set_rate(scale3d.clk_3d2, scale3d.max_rate_3d);
170 if (scale3d.p_scale_emc)
171 clk_set_rate(scale3d.clk_3d_emc,
172 clk_round_rate(scale3d.clk_3d_emc, UINT_MAX));
173 }
174}
175
176static int scale3d_is_enabled(void)
177{
178 int enable;
179
180 if (!scale3d.enable)
181 return 0;
182
183 mutex_lock(&scale3d.lock);
184 enable = scale3d.enable;
185 mutex_unlock(&scale3d.lock);
186
187 return enable;
188}
189
190static void scale3d_enable(int enable)
191{
192 int disable = 0;
193
194 mutex_lock(&scale3d.lock);
195
196 if (enable) {
197 if (scale3d.max_rate_3d != scale3d.min_rate_3d)
198 scale3d.enable = 1;
199 } else {
200 scale3d.enable = 0;
201 disable = 1;
202 }
203
204 mutex_unlock(&scale3d.lock);
205
206 if (disable)
207 reset_3d_clocks();
208}
209
210static void reset_scaling_counters(ktime_t time)
211{
212 scale3d.idle_total = 0;
213 scale3d.idle_short_term_total = 0;
214 scale3d.last_idle = time;
215 scale3d.last_short_term_idle = time;
216 scale3d.idle_frame = time;
217}
218
219/* scaling_adjust - use scale up / scale down hint counts to adjust scaling
220 * parameters.
221 *
222 * hint_ratio is 100 x the ratio of scale up to scale down hints. Three cases
223 * are distinguished:
224 *
225 * hint_ratio < HINT_RATIO_MIN - set parameters to maximize scaling effect
226 * hint_ratio > HINT_RATIO_MAX - set parameters to minimize scaling effect
227 * hint_ratio between limits - scale parameters linearly
228 *
229 * the parameters adjusted are
230 *
231 * * fast_response time
232 * * period - time for scaling down estimate
233 * * idle_min percentage
234 * * idle_max percentage
235 */
236#define SCALING_ADJUST_PERIOD 1000000
237#define HINT_RATIO_MAX 400
238#define HINT_RATIO_MIN 100
239#define HINT_RATIO_MID ((HINT_RATIO_MAX + HINT_RATIO_MIN) / 2)
240#define HINT_RATIO_DIFF (HINT_RATIO_MAX - HINT_RATIO_MIN)
241
242static void scaling_adjust(ktime_t time)
243{
244 long hint_ratio;
245 long fast_response_adjustment;
246 long period_adjustment;
247 int idle_min_adjustment;
248 int idle_max_adjustment;
249 unsigned long dt;
250
251 dt = (unsigned long) ktime_us_delta(time, scale3d.last_tweak);
252 if (dt < SCALING_ADJUST_PERIOD)
253 return;
254
255 hint_ratio = (100 * (scale3d.fast_up_count + 1)) /
256 (scale3d.slow_down_count + 1);
257
258 if (hint_ratio > HINT_RATIO_MAX) {
259 fast_response_adjustment = -((int) scale3d.p_fast_response) / 4;
260 period_adjustment = scale3d.p_period / 2;
261 idle_min_adjustment = scale3d.p_idle_min;
262 idle_max_adjustment = scale3d.p_idle_max;
263 } else if (hint_ratio < HINT_RATIO_MIN) {
264 fast_response_adjustment = scale3d.p_fast_response / 2;
265 period_adjustment = -((int) scale3d.p_period) / 4;
266 idle_min_adjustment = -((int) scale3d.p_idle_min) / 2;
267 idle_max_adjustment = -((int) scale3d.p_idle_max) / 2;
268 } else {
269 int diff;
270 int factor;
271
272 diff = HINT_RATIO_MID - hint_ratio;
273 if (diff < 0)
274 factor = -diff * 2;
275 else {
276 factor = -diff;
277 diff *= 2;
278 }
279
280 fast_response_adjustment = diff *
281 (scale3d.p_fast_response / (HINT_RATIO_DIFF * 2));
282 period_adjustment =
283 diff * (scale3d.p_period / HINT_RATIO_DIFF);
284 idle_min_adjustment =
285 (factor * (int) scale3d.p_idle_min) / HINT_RATIO_DIFF;
286 idle_max_adjustment =
287 (factor * (int) scale3d.p_idle_max) / HINT_RATIO_DIFF;
288 }
289
290 scale3d.fast_response =
291 scale3d.p_fast_response + fast_response_adjustment;
292 scale3d.period = scale3d.p_period + period_adjustment;
293 scale3d.idle_min = scale3d.p_idle_min + idle_min_adjustment;
294 scale3d.idle_max = scale3d.p_idle_max + idle_max_adjustment;
295
296 if (scale3d.p_verbosity >= 10)
297 pr_info("scale3d stats: + %d - %d (/ %d) f %u p %u min %u max %u\n",
298 scale3d.fast_up_count, scale3d.slow_down_count,
299 scale3d.fast_responses, scale3d.fast_response,
300 scale3d.period, scale3d.idle_min, scale3d.idle_max);
301
302 scale3d.fast_up_count = 0;
303 scale3d.slow_down_count = 0;
304 scale3d.fast_responses = 0;
305 scale3d.last_down = time;
306 scale3d.last_tweak = time;
307}
308
309#undef SCALING_ADJUST_PERIOD
310#undef HINT_RATIO_MAX
311#undef HINT_RATIO_MIN
312#undef HINT_RATIO_MID
313#undef HINT_RATIO_DIFF
314
315static void scaling_state_check(ktime_t time)
316{
317 unsigned long dt;
318
319 /* adjustment: set scale parameters (fast_response, period) +/- 25%
320 * based on ratio of scale up to scale down hints
321 */
322 if (scale3d.p_adjust)
323 scaling_adjust(time);
324 else {
325 scale3d.fast_response = scale3d.p_fast_response;
326 scale3d.period = scale3d.p_period;
327 scale3d.idle_min = scale3d.p_idle_min;
328 scale3d.idle_max = scale3d.p_idle_max;
329 }
330
331 /* check for load peaks */
332 dt = (unsigned long) ktime_us_delta(time, scale3d.fast_frame);
333 if (dt > scale3d.fast_response) {
334 unsigned long idleness =
335 (scale3d.idle_short_term_total * 100) / dt;
336 scale3d.fast_responses++;
337 scale3d.fast_frame = time;
338 /* if too busy, scale up */
339 if (idleness < scale3d.idle_min) {
340 scale3d.is_scaled = 0;
341 scale3d.fast_up_count++;
342 if (scale3d.p_verbosity >= 5)
343 pr_info("scale3d: %ld%% busy\n",
344 100 - idleness);
345
346 reset_3d_clocks();
347 reset_scaling_counters(time);
348 return;
349 }
350 scale3d.idle_short_term_total = 0;
351 scale3d.last_short_term_idle = time;
352 }
353
354 dt = (unsigned long) ktime_us_delta(time, scale3d.idle_frame);
355 if (dt > scale3d.period) {
356 unsigned long idleness = (scale3d.idle_total * 100) / dt;
357
358 if (scale3d.p_verbosity >= 5)
359 pr_info("scale3d: idle %lu, ~%lu%%\n",
360 scale3d.idle_total, idleness);
361
362 if (idleness > scale3d.idle_max) {
363 if (!scale3d.is_scaled) {
364 scale3d.is_scaled = 1;
365 scale3d.last_down = time;
366 }
367 scale3d.slow_down_count++;
368 /* if idle time is high, clock down */
369 scale3d.scale = 100 - (idleness - scale3d.idle_min);
370 schedule_work(&scale3d.work);
371 }
372
373 reset_scaling_counters(time);
374 }
375}
376
377void nvhost_scale3d_notify_idle(struct nvhost_device *dev)
378{
379 ktime_t t;
380 unsigned long dt;
381
382 if (!scale3d.enable)
383 return;
384
385 mutex_lock(&scale3d.lock);
386
387 t = ktime_get();
388
389 if (scale3d.is_idle) {
390 dt = ktime_us_delta(t, scale3d.last_idle);
391 scale3d.idle_total += dt;
392 dt = ktime_us_delta(t, scale3d.last_short_term_idle);
393 scale3d.idle_short_term_total += dt;
394 } else
395 scale3d.is_idle = 1;
396
397 scale3d.last_idle = t;
398 scale3d.last_short_term_idle = t;
399
400 scaling_state_check(scale3d.last_idle);
401
402 /* delay idle_max % of 2 * fast_response time (given in microseconds) */
403 schedule_delayed_work(&scale3d.idle_timer,
404 msecs_to_jiffies((scale3d.idle_max * scale3d.fast_response)
405 / 50000));
406
407 mutex_unlock(&scale3d.lock);
408}
409
410void nvhost_scale3d_notify_busy(struct nvhost_device *dev)
411{
412 unsigned long idle;
413 unsigned long short_term_idle;
414 ktime_t t;
415
416 if (!scale3d.enable)
417 return;
418
419 mutex_lock(&scale3d.lock);
420
421 cancel_delayed_work(&scale3d.idle_timer);
422
423 t = ktime_get();
424
425 if (scale3d.is_idle) {
426 idle = (unsigned long)
427 ktime_us_delta(t, scale3d.last_idle);
428 scale3d.idle_total += idle;
429 short_term_idle =
430 ktime_us_delta(t, scale3d.last_short_term_idle);
431 scale3d.idle_short_term_total += short_term_idle;
432 scale3d.is_idle = 0;
433 }
434
435 scaling_state_check(t);
436
437 mutex_unlock(&scale3d.lock);
438}
439
440static void scale3d_idle_handler(struct work_struct *work)
441{
442 int notify_idle = 0;
443
444 if (!scale3d.enable)
445 return;
446
447 mutex_lock(&scale3d.lock);
448
449 if (scale3d.is_idle && tegra_is_clk_enabled(scale3d.clk_3d)) {
450 unsigned long curr = clk_get_rate(scale3d.clk_3d);
451 if (curr > scale3d.min_rate_3d)
452 notify_idle = 1;
453 }
454
455 mutex_unlock(&scale3d.lock);
456
457 if (notify_idle)
458 nvhost_scale3d_notify_idle(NULL);
459}
460
461void nvhost_scale3d_reset()
462{
463 ktime_t t;
464
465 if (!scale3d.enable)
466 return;
467
468 t = ktime_get();
469 mutex_lock(&scale3d.lock);
470 reset_scaling_counters(t);
471 mutex_unlock(&scale3d.lock);
472}
473
474/*
475 * debugfs parameters to control 3d clock scaling
476 */
477
478void nvhost_scale3d_debug_init(struct dentry *de)
479{
480 struct dentry *d, *f;
481
482 d = debugfs_create_dir("scaling", de);
483 if (!d) {
484 pr_err("scale3d: can\'t create debugfs directory\n");
485 return;
486 }
487
488#define CREATE_SCALE3D_FILE(fname) \
489 do {\
490 f = debugfs_create_u32(#fname, S_IRUGO | S_IWUSR, d,\
491 &scale3d.p_##fname);\
492 if (NULL == f) {\
493 pr_err("scale3d: can\'t create file " #fname "\n");\
494 return;\
495 } \
496 } while (0)
497
498 CREATE_SCALE3D_FILE(fast_response);
499 CREATE_SCALE3D_FILE(idle_min);
500 CREATE_SCALE3D_FILE(idle_max);
501 CREATE_SCALE3D_FILE(period);
502 CREATE_SCALE3D_FILE(adjust);
503 CREATE_SCALE3D_FILE(scale_emc);
504 CREATE_SCALE3D_FILE(emc_dip);
505 CREATE_SCALE3D_FILE(verbosity);
506#undef CREATE_SCALE3D_FILE
507}
508
509static ssize_t enable_3d_scaling_show(struct device *device,
510 struct device_attribute *attr, char *buf)
511{
512 ssize_t res;
513
514 res = snprintf(buf, PAGE_SIZE, "%d\n", scale3d_is_enabled());
515
516 return res;
517}
518
519static ssize_t enable_3d_scaling_store(struct device *dev,
520 struct device_attribute *attr, const char *buf, size_t count)
521{
522 unsigned long val = 0;
523
524 if (strict_strtoul(buf, 10, &val) < 0)
525 return -EINVAL;
526
527 scale3d_enable(val);
528
529 return count;
530}
531
532static DEVICE_ATTR(enable_3d_scaling, S_IRUGO | S_IWUSR,
533 enable_3d_scaling_show, enable_3d_scaling_store);
534
535void nvhost_scale3d_init(struct nvhost_device *d)
536{
537 if (!scale3d.init) {
538 int error;
539 unsigned long max_emc, min_emc;
540 long correction;
541 mutex_init(&scale3d.lock);
542
543 scale3d.clk_3d = d->clk[0];
544 if (tegra_get_chipid() == TEGRA_CHIPID_TEGRA3) {
545 scale3d.clk_3d2 = d->clk[1];
546 scale3d.clk_3d_emc = d->clk[2];
547 } else
548 scale3d.clk_3d_emc = d->clk[1];
549
550 scale3d.max_rate_3d = clk_round_rate(scale3d.clk_3d, UINT_MAX);
551 scale3d.min_rate_3d = clk_round_rate(scale3d.clk_3d, 0);
552
553 if (scale3d.max_rate_3d == scale3d.min_rate_3d) {
554 pr_warn("scale3d: 3d max rate = min rate (%lu), "
555 "disabling\n", scale3d.max_rate_3d);
556 scale3d.enable = 0;
557 return;
558 }
559
560 /* emc scaling:
561 *
562 * Remc = S * R3d + O - (Sd * (R3d - Rm)^2 + Od)
563 *
564 * Remc - 3d.emc rate
565 * R3d - 3d.cbus rate
566 * Rm - 3d.cbus 'middle' rate = (max + min)/2
567 * S - emc_slope
568 * O - emc_offset
569 * Sd - emc_dip_slope
570 * Od - emc_dip_offset
571 *
572 * this superposes a quadratic dip centered around the middle 3d
573 * frequency over a linear correlation of 3d.emc to 3d clock
574 * rates.
575 *
576 * S, O are chosen so that the maximum 3d rate produces the
577 * maximum 3d.emc rate exactly, and the minimum 3d rate produces
578 * at least the minimum 3d.emc rate.
579 *
580 * Sd and Od are chosen to produce the largest dip that will
581 * keep 3d.emc frequencies monotonously decreasing with 3d
582 * frequencies. To achieve this, the first derivative of Remc
583 * with respect to R3d should be zero for the minimal 3d rate:
584 *
585 * R'emc = S - 2 * Sd * (R3d - Rm)
586 * R'emc(R3d-min) = 0
587 * S = 2 * Sd * (R3d-min - Rm)
588 * = 2 * Sd * (R3d-min - R3d-max) / 2
589 * Sd = S / (R3d-min - R3d-max)
590 *
591 * +---------------------------------------------------+
592 * | Sd = -(emc-max - emc-min) / (R3d-min - R3d-max)^2 |
593 * +---------------------------------------------------+
594 *
595 * dip = Sd * (R3d - Rm)^2 + Od
596 *
597 * requiring dip(R3d-min) = 0 and dip(R3d-max) = 0 gives
598 *
599 * Sd * (R3d-min - Rm)^2 + Od = 0
600 * Od = -Sd * ((R3d-min - R3d-max) / 2)^2
601 * = -Sd * ((R3d-min - R3d-max)^2) / 4
602 *
603 * +------------------------------+
604 * | Od = (emc-max - emc-min) / 4 |
605 * +------------------------------+
606 */
607
608 max_emc = clk_round_rate(scale3d.clk_3d_emc, UINT_MAX);
609 min_emc = clk_round_rate(scale3d.clk_3d_emc, 0);
610
611 scale3d.emc_slope = (max_emc - min_emc) /
612 (scale3d.max_rate_3d - scale3d.min_rate_3d);
613 scale3d.emc_offset = max_emc -
614 scale3d.emc_slope * scale3d.max_rate_3d;
615 /* guarantee max 3d rate maps to max emc rate */
616 scale3d.emc_offset += max_emc -
617 (scale3d.emc_slope * scale3d.max_rate_3d +
618 scale3d.emc_offset);
619
620 scale3d.emc_dip_offset = (max_emc - min_emc) / 4;
621 scale3d.emc_dip_slope =
622 -4 * (scale3d.emc_dip_offset /
623 (POW2(scale3d.max_rate_3d - scale3d.min_rate_3d)));
624 scale3d.emc_xmid =
625 (scale3d.max_rate_3d + scale3d.min_rate_3d) / 2;
626 correction =
627 scale3d.emc_dip_offset +
628 scale3d.emc_dip_slope *
629 POW2(scale3d.max_rate_3d - scale3d.emc_xmid);
630 scale3d.emc_dip_offset -= correction;
631
632 INIT_WORK(&scale3d.work, scale3d_clocks_handler);
633 INIT_DELAYED_WORK(&scale3d.idle_timer, scale3d_idle_handler);
634
635 /* set scaling parameter defaults */
636 scale3d.enable = 1;
637 scale3d.period = scale3d.p_period = 100000;
638 scale3d.idle_min = scale3d.p_idle_min = 10;
639 scale3d.idle_max = scale3d.p_idle_max = 15;
640 scale3d.fast_response = scale3d.p_fast_response = 7000;
641 scale3d.p_scale_emc = 1;
642 scale3d.p_emc_dip = 1;
643 scale3d.p_verbosity = 0;
644 scale3d.p_adjust = 1;
645
646 error = device_create_file(&d->dev,
647 &dev_attr_enable_3d_scaling);
648 if (error)
649 dev_err(&d->dev, "failed to create sysfs attributes");
650
651 scale3d.init = 1;
652 }
653
654 nvhost_scale3d_reset();
655}
656
657void nvhost_scale3d_deinit(struct nvhost_device *dev)
658{
659 device_remove_file(&dev->dev, &dev_attr_enable_3d_scaling);
660 scale3d.init = 0;
661}
diff --git a/drivers/video/tegra/host/gr3d/scale3d.h b/drivers/video/tegra/host/gr3d/scale3d.h
new file mode 100644
index 00000000000..f8aae1d591a
--- /dev/null
+++ b/drivers/video/tegra/host/gr3d/scale3d.h
@@ -0,0 +1,47 @@
1/*
2 * drivers/video/tegra/host/t30/scale3d.h
3 *
4 * Tegra Graphics Host 3D Clock Scaling
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef NVHOST_T30_SCALE3D_H
22#define NVHOST_T30_SCALE3D_H
23
24struct nvhost_device;
25struct device;
26struct dentry;
27
28/* Initialization and de-initialization for module */
29void nvhost_scale3d_init(struct nvhost_device *);
30void nvhost_scale3d_deinit(struct nvhost_device *);
31
32/* Suspend is called when powering down module */
33void nvhost_scale3d_suspend(struct nvhost_device *);
34
35/* reset 3d module load counters, called on resume */
36void nvhost_scale3d_reset(void);
37
38/*
39 * call when performing submit to notify scaling mechanism that 3d module is
40 * in use
41 */
42void nvhost_scale3d_notify_busy(struct nvhost_device *);
43void nvhost_scale3d_notify_idle(struct nvhost_device *);
44
45void nvhost_scale3d_debug_init(struct dentry *de);
46
47#endif
diff --git a/drivers/video/tegra/host/host1x/Makefile b/drivers/video/tegra/host/host1x/Makefile
new file mode 100644
index 00000000000..c3214ffe147
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/Makefile
@@ -0,0 +1,12 @@
1GCOV_PROFILE := y
2
3EXTRA_CFLAGS += -Idrivers/video/tegra/host
4
5nvhost-host1x-objs = \
6 host1x_syncpt.o \
7 host1x_channel.o \
8 host1x_intr.o \
9 host1x_cdma.o \
10 host1x_debug.o
11
12obj-$(CONFIG_TEGRA_GRHOST) += nvhost-host1x.o
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.c b/drivers/video/tegra/host/host1x/host1x_cdma.c
new file mode 100644
index 00000000000..cdd6026718b
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.c
@@ -0,0 +1,665 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_cdma.c
3 *
4 * Tegra Graphics Host Command DMA
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/slab.h>
22#include "nvhost_cdma.h"
23#include "dev.h"
24
25#include "host1x_hardware.h"
26#include "host1x_syncpt.h"
27#include "host1x_cdma.h"
28#include "host1x_hwctx.h"
29
30static inline u32 host1x_channel_dmactrl(int stop, int get_rst, int init_get)
31{
32 return HOST1X_CREATE(CHANNEL_DMACTRL, DMASTOP, stop)
33 | HOST1X_CREATE(CHANNEL_DMACTRL, DMAGETRST, get_rst)
34 | HOST1X_CREATE(CHANNEL_DMACTRL, DMAINITGET, init_get);
35}
36
37static void cdma_timeout_handler(struct work_struct *work);
38
39/*
40 * push_buffer
41 *
42 * The push buffer is a circular array of words to be fetched by command DMA.
43 * Note that it works slightly differently to the sync queue; fence == cur
44 * means that the push buffer is full, not empty.
45 */
46
47
48/**
49 * Reset to empty push buffer
50 */
51static void push_buffer_reset(struct push_buffer *pb)
52{
53 pb->fence = PUSH_BUFFER_SIZE - 8;
54 pb->cur = 0;
55}
56
57/**
58 * Init push buffer resources
59 */
60static int push_buffer_init(struct push_buffer *pb)
61{
62 struct nvhost_cdma *cdma = pb_to_cdma(pb);
63 struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
64 pb->mem = NULL;
65 pb->mapped = NULL;
66 pb->phys = 0;
67 pb->nvmap = NULL;
68
69 BUG_ON(!cdma_pb_op(cdma).reset);
70 cdma_pb_op(cdma).reset(pb);
71
72 /* allocate and map pushbuffer memory */
73 pb->mem = nvmap_alloc(nvmap, PUSH_BUFFER_SIZE + 4, 32,
74 NVMAP_HANDLE_WRITE_COMBINE, 0);
75 if (IS_ERR_OR_NULL(pb->mem)) {
76 pb->mem = NULL;
77 goto fail;
78 }
79 pb->mapped = nvmap_mmap(pb->mem);
80 if (pb->mapped == NULL)
81 goto fail;
82
83 /* pin pushbuffer and get physical address */
84 pb->phys = nvmap_pin(nvmap, pb->mem);
85 if (pb->phys >= 0xfffff000) {
86 pb->phys = 0;
87 goto fail;
88 }
89
90 /* memory for storing nvmap client and handles for each opcode pair */
91 pb->nvmap = kzalloc(NVHOST_GATHER_QUEUE_SIZE *
92 sizeof(struct nvmap_client_handle),
93 GFP_KERNEL);
94 if (!pb->nvmap)
95 goto fail;
96
97 /* put the restart at the end of pushbuffer memory */
98 *(pb->mapped + (PUSH_BUFFER_SIZE >> 2)) =
99 nvhost_opcode_restart(pb->phys);
100
101 return 0;
102
103fail:
104 cdma_pb_op(cdma).destroy(pb);
105 return -ENOMEM;
106}
107
108/**
109 * Clean up push buffer resources
110 */
111static void push_buffer_destroy(struct push_buffer *pb)
112{
113 struct nvhost_cdma *cdma = pb_to_cdma(pb);
114 struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
115 if (pb->mapped)
116 nvmap_munmap(pb->mem, pb->mapped);
117
118 if (pb->phys != 0)
119 nvmap_unpin(nvmap, pb->mem);
120
121 if (pb->mem)
122 nvmap_free(nvmap, pb->mem);
123
124 kfree(pb->nvmap);
125
126 pb->mem = NULL;
127 pb->mapped = NULL;
128 pb->phys = 0;
129 pb->nvmap = 0;
130}
131
132/**
133 * Push two words to the push buffer
134 * Caller must ensure push buffer is not full
135 */
136static void push_buffer_push_to(struct push_buffer *pb,
137 struct nvmap_client *client,
138 struct nvmap_handle *handle, u32 op1, u32 op2)
139{
140 u32 cur = pb->cur;
141 u32 *p = (u32 *)((u32)pb->mapped + cur);
142 u32 cur_nvmap = (cur/8) & (NVHOST_GATHER_QUEUE_SIZE - 1);
143 BUG_ON(cur == pb->fence);
144 *(p++) = op1;
145 *(p++) = op2;
146 pb->nvmap[cur_nvmap].client = client;
147 pb->nvmap[cur_nvmap].handle = handle;
148 pb->cur = (cur + 8) & (PUSH_BUFFER_SIZE - 1);
149}
150
151/**
152 * Pop a number of two word slots from the push buffer
153 * Caller must ensure push buffer is not empty
154 */
155static void push_buffer_pop_from(struct push_buffer *pb,
156 unsigned int slots)
157{
158 /* Clear the nvmap references for old items from pb */
159 unsigned int i;
160 u32 fence_nvmap = pb->fence/8;
161 for (i = 0; i < slots; i++) {
162 int cur_fence_nvmap = (fence_nvmap+i)
163 & (NVHOST_GATHER_QUEUE_SIZE - 1);
164 struct nvmap_client_handle *h =
165 &pb->nvmap[cur_fence_nvmap];
166 h->client = NULL;
167 h->handle = NULL;
168 }
169 /* Advance the next write position */
170 pb->fence = (pb->fence + slots * 8) & (PUSH_BUFFER_SIZE - 1);
171}
172
173/**
174 * Return the number of two word slots free in the push buffer
175 */
176static u32 push_buffer_space(struct push_buffer *pb)
177{
178 return ((pb->fence - pb->cur) & (PUSH_BUFFER_SIZE - 1)) / 8;
179}
180
181static u32 push_buffer_putptr(struct push_buffer *pb)
182{
183 return pb->phys + pb->cur;
184}
185
186/*
187 * The syncpt incr buffer is filled with methods to increment syncpts, which
188 * is later GATHER-ed into the mainline PB. It's used when a timed out context
189 * is interleaved with other work, so needs to inline the syncpt increments
190 * to maintain the count (but otherwise does no work).
191 */
192
193/**
194 * Init timeout and syncpt incr buffer resources
195 */
196static int cdma_timeout_init(struct nvhost_cdma *cdma,
197 u32 syncpt_id)
198{
199 struct nvhost_master *dev = cdma_to_dev(cdma);
200 struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
201 struct syncpt_buffer *sb = &cdma->syncpt_buffer;
202 struct nvhost_channel *ch = cdma_to_channel(cdma);
203 u32 i = 0;
204
205 if (syncpt_id == NVSYNCPT_INVALID)
206 return -EINVAL;
207
208 /* allocate and map syncpt incr memory */
209 sb->mem = nvmap_alloc(nvmap,
210 (SYNCPT_INCR_BUFFER_SIZE_WORDS * sizeof(u32)), 32,
211 NVMAP_HANDLE_WRITE_COMBINE, 0);
212 if (IS_ERR_OR_NULL(sb->mem)) {
213 sb->mem = NULL;
214 goto fail;
215 }
216 sb->mapped = nvmap_mmap(sb->mem);
217 if (sb->mapped == NULL)
218 goto fail;
219
220 /* pin syncpt buffer and get physical address */
221 sb->phys = nvmap_pin(nvmap, sb->mem);
222 if (sb->phys >= 0xfffff000) {
223 sb->phys = 0;
224 goto fail;
225 }
226
227 dev_dbg(&dev->dev->dev, "%s: SYNCPT_INCR buffer at 0x%x\n",
228 __func__, sb->phys);
229
230 sb->words_per_incr = (syncpt_id == NVSYNCPT_3D) ? 5 : 3;
231 sb->incr_per_buffer = (SYNCPT_INCR_BUFFER_SIZE_WORDS /
232 sb->words_per_incr);
233
234 /* init buffer with SETCL and INCR_SYNCPT methods */
235 while (i < sb->incr_per_buffer) {
236 sb->mapped[i++] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
237 0, 0);
238 sb->mapped[i++] = nvhost_opcode_imm_incr_syncpt(
239 NV_SYNCPT_IMMEDIATE,
240 syncpt_id);
241 if (syncpt_id == NVSYNCPT_3D) {
242 /* also contains base increments */
243 sb->mapped[i++] = nvhost_opcode_nonincr(
244 NV_CLASS_HOST_INCR_SYNCPT_BASE,
245 1);
246 sb->mapped[i++] = nvhost_class_host_incr_syncpt_base(
247 NVWAITBASE_3D, 1);
248 }
249 sb->mapped[i++] = nvhost_opcode_setclass(ch->dev->class,
250 0, 0);
251 }
252 wmb();
253
254 INIT_DELAYED_WORK(&cdma->timeout.wq, cdma_timeout_handler);
255 cdma->timeout.initialized = true;
256
257 return 0;
258fail:
259 cdma_op(cdma).timeout_destroy(cdma);
260 return -ENOMEM;
261}
262
263/**
264 * Clean up timeout syncpt buffer resources
265 */
266static void cdma_timeout_destroy(struct nvhost_cdma *cdma)
267{
268 struct nvmap_client *nvmap = cdma_to_nvmap(cdma);
269 struct syncpt_buffer *sb = &cdma->syncpt_buffer;
270
271 if (sb->mapped)
272 nvmap_munmap(sb->mem, sb->mapped);
273
274 if (sb->phys != 0)
275 nvmap_unpin(nvmap, sb->mem);
276
277 if (sb->mem)
278 nvmap_free(nvmap, sb->mem);
279
280 sb->mem = NULL;
281 sb->mapped = NULL;
282 sb->phys = 0;
283
284 if (cdma->timeout.initialized)
285 cancel_delayed_work(&cdma->timeout.wq);
286 cdma->timeout.initialized = false;
287}
288
289/**
290 * Increment timedout buffer's syncpt via CPU.
291 */
292static void cdma_timeout_cpu_incr(struct nvhost_cdma *cdma, u32 getptr,
293 u32 syncpt_incrs, u32 syncval, u32 nr_slots)
294{
295 struct nvhost_master *dev = cdma_to_dev(cdma);
296 struct push_buffer *pb = &cdma->push_buffer;
297 u32 i, getidx;
298
299 for (i = 0; i < syncpt_incrs; i++)
300 nvhost_syncpt_cpu_incr(&dev->syncpt, cdma->timeout.syncpt_id);
301
302 /* after CPU incr, ensure shadow is up to date */
303 nvhost_syncpt_update_min(&dev->syncpt, cdma->timeout.syncpt_id);
304
305 /* update WAITBASE_3D by same number of incrs */
306 if (cdma->timeout.syncpt_id == NVSYNCPT_3D) {
307 void __iomem *p;
308 p = dev->sync_aperture + HOST1X_SYNC_SYNCPT_BASE_0 +
309 (NVWAITBASE_3D * sizeof(u32));
310 writel(syncval, p);
311 }
312
313 /* NOP all the PB slots */
314 getidx = getptr - pb->phys;
315 while (nr_slots--) {
316 u32 *p = (u32 *)((u32)pb->mapped + getidx);
317 *(p++) = NVHOST_OPCODE_NOOP;
318 *(p++) = NVHOST_OPCODE_NOOP;
319 dev_dbg(&dev->dev->dev, "%s: NOP at 0x%x\n",
320 __func__, pb->phys + getidx);
321 getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
322 }
323 wmb();
324}
325
326/**
327 * This routine is called at the point we transition back into a timed
328 * ctx. The syncpts are incremented via pushbuffer with a flag indicating
329 * whether there's a CTXSAVE that should be still executed (for the
330 * preceding HW ctx).
331 */
332static void cdma_timeout_pb_incr(struct nvhost_cdma *cdma, u32 getptr,
333 u32 syncpt_incrs, u32 nr_slots,
334 bool exec_ctxsave)
335{
336 struct nvhost_master *dev = cdma_to_dev(cdma);
337 struct syncpt_buffer *sb = &cdma->syncpt_buffer;
338 struct push_buffer *pb = &cdma->push_buffer;
339 struct host1x_hwctx *hwctx = to_host1x_hwctx(cdma->timeout.ctx);
340 u32 getidx, *p;
341
342 /* should have enough slots to incr to desired count */
343 BUG_ON(syncpt_incrs > (nr_slots * sb->incr_per_buffer));
344
345 getidx = getptr - pb->phys;
346 if (exec_ctxsave) {
347 /* don't disrupt the CTXSAVE of a good/non-timed out ctx */
348 nr_slots -= hwctx->save_slots;
349 syncpt_incrs -= hwctx->save_incrs;
350
351 getidx += (hwctx->save_slots * 8);
352 getidx &= (PUSH_BUFFER_SIZE - 1);
353
354 dev_dbg(&dev->dev->dev,
355 "%s: exec CTXSAVE of prev ctx (slots %d, incrs %d)\n",
356 __func__, nr_slots, syncpt_incrs);
357 }
358
359 while (syncpt_incrs) {
360 u32 incrs, count;
361
362 /* GATHER count are incrs * number of DWORDs per incr */
363 incrs = min(syncpt_incrs, sb->incr_per_buffer);
364 count = incrs * sb->words_per_incr;
365
366 p = (u32 *)((u32)pb->mapped + getidx);
367 *(p++) = nvhost_opcode_gather(count);
368 *(p++) = sb->phys;
369
370 dev_dbg(&dev->dev->dev,
371 "%s: GATHER at 0x%x, from 0x%x, dcount = %d\n",
372 __func__,
373 pb->phys + getidx, sb->phys,
374 (incrs * sb->words_per_incr));
375
376 syncpt_incrs -= incrs;
377 getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
378 nr_slots--;
379 }
380
381 /* NOP remaining slots */
382 while (nr_slots--) {
383 p = (u32 *)((u32)pb->mapped + getidx);
384 *(p++) = NVHOST_OPCODE_NOOP;
385 *(p++) = NVHOST_OPCODE_NOOP;
386 dev_dbg(&dev->dev->dev, "%s: NOP at 0x%x\n",
387 __func__, pb->phys + getidx);
388 getidx = (getidx + 8) & (PUSH_BUFFER_SIZE - 1);
389 }
390 wmb();
391}
392
393/**
394 * Start channel DMA
395 */
396static void cdma_start(struct nvhost_cdma *cdma)
397{
398 void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
399
400 if (cdma->running)
401 return;
402
403 BUG_ON(!cdma_pb_op(cdma).putptr);
404 cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
405
406 writel(host1x_channel_dmactrl(true, false, false),
407 chan_regs + HOST1X_CHANNEL_DMACTRL);
408
409 /* set base, put, end pointer (all of memory) */
410 writel(0, chan_regs + HOST1X_CHANNEL_DMASTART);
411 writel(cdma->last_put, chan_regs + HOST1X_CHANNEL_DMAPUT);
412 writel(0xFFFFFFFF, chan_regs + HOST1X_CHANNEL_DMAEND);
413
414 /* reset GET */
415 writel(host1x_channel_dmactrl(true, true, true),
416 chan_regs + HOST1X_CHANNEL_DMACTRL);
417
418 /* start the command DMA */
419 writel(host1x_channel_dmactrl(false, false, false),
420 chan_regs + HOST1X_CHANNEL_DMACTRL);
421
422 cdma->running = true;
423}
424
425/**
426 * Similar to cdma_start(), but rather than starting from an idle
427 * state (where DMA GET is set to DMA PUT), on a timeout we restore
428 * DMA GET from an explicit value (so DMA may again be pending).
429 */
430static void cdma_timeout_restart(struct nvhost_cdma *cdma, u32 getptr)
431{
432 struct nvhost_master *dev = cdma_to_dev(cdma);
433 void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
434
435 if (cdma->running)
436 return;
437
438 BUG_ON(!cdma_pb_op(cdma).putptr);
439 cdma->last_put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
440
441 writel(host1x_channel_dmactrl(true, false, false),
442 chan_regs + HOST1X_CHANNEL_DMACTRL);
443
444 /* set base, end pointer (all of memory) */
445 writel(0, chan_regs + HOST1X_CHANNEL_DMASTART);
446 writel(0xFFFFFFFF, chan_regs + HOST1X_CHANNEL_DMAEND);
447
448 /* set GET, by loading the value in PUT (then reset GET) */
449 writel(getptr, chan_regs + HOST1X_CHANNEL_DMAPUT);
450 writel(host1x_channel_dmactrl(true, true, true),
451 chan_regs + HOST1X_CHANNEL_DMACTRL);
452
453 dev_dbg(&dev->dev->dev,
454 "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n",
455 __func__,
456 readl(chan_regs + HOST1X_CHANNEL_DMAGET),
457 readl(chan_regs + HOST1X_CHANNEL_DMAPUT),
458 cdma->last_put);
459
460 /* deassert GET reset and set PUT */
461 writel(host1x_channel_dmactrl(true, false, false),
462 chan_regs + HOST1X_CHANNEL_DMACTRL);
463 writel(cdma->last_put, chan_regs + HOST1X_CHANNEL_DMAPUT);
464
465 /* start the command DMA */
466 writel(host1x_channel_dmactrl(false, false, false),
467 chan_regs + HOST1X_CHANNEL_DMACTRL);
468
469 cdma->running = true;
470}
471
472/**
473 * Kick channel DMA into action by writing its PUT offset (if it has changed)
474 */
475static void cdma_kick(struct nvhost_cdma *cdma)
476{
477 u32 put;
478 BUG_ON(!cdma_pb_op(cdma).putptr);
479
480 put = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
481
482 if (put != cdma->last_put) {
483 void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
484 wmb();
485 writel(put, chan_regs + HOST1X_CHANNEL_DMAPUT);
486 cdma->last_put = put;
487 }
488}
489
490static void cdma_stop(struct nvhost_cdma *cdma)
491{
492 void __iomem *chan_regs = cdma_to_channel(cdma)->aperture;
493
494 mutex_lock(&cdma->lock);
495 if (cdma->running) {
496 nvhost_cdma_wait_locked(cdma, CDMA_EVENT_SYNC_QUEUE_EMPTY);
497 writel(host1x_channel_dmactrl(true, false, false),
498 chan_regs + HOST1X_CHANNEL_DMACTRL);
499 cdma->running = false;
500 }
501 mutex_unlock(&cdma->lock);
502}
503
504/**
505 * Retrieve the op pair at a slot offset from a DMA address
506 */
507void cdma_peek(struct nvhost_cdma *cdma,
508 u32 dmaget, int slot, u32 *out)
509{
510 u32 offset = dmaget - cdma->push_buffer.phys;
511 u32 *p = cdma->push_buffer.mapped;
512
513 offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
514 out[0] = p[offset];
515 out[1] = p[offset + 1];
516}
517
518/**
519 * Stops both channel's command processor and CDMA immediately.
520 * Also, tears down the channel and resets corresponding module.
521 */
522void cdma_timeout_teardown_begin(struct nvhost_cdma *cdma)
523{
524 struct nvhost_master *dev = cdma_to_dev(cdma);
525 struct nvhost_channel *ch = cdma_to_channel(cdma);
526 u32 cmdproc_stop;
527
528 BUG_ON(cdma->torndown);
529
530 dev_dbg(&dev->dev->dev,
531 "begin channel teardown (channel id %d)\n", ch->chid);
532
533 cmdproc_stop = readl(dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
534 cmdproc_stop |= BIT(ch->chid);
535 writel(cmdproc_stop, dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
536
537 dev_dbg(&dev->dev->dev,
538 "%s: DMA GET 0x%x, PUT HW 0x%x / shadow 0x%x\n",
539 __func__,
540 readl(ch->aperture + HOST1X_CHANNEL_DMAGET),
541 readl(ch->aperture + HOST1X_CHANNEL_DMAPUT),
542 cdma->last_put);
543
544 writel(host1x_channel_dmactrl(true, false, false),
545 ch->aperture + HOST1X_CHANNEL_DMACTRL);
546
547 writel(BIT(ch->chid), dev->sync_aperture + HOST1X_SYNC_CH_TEARDOWN);
548 nvhost_module_reset(ch->dev);
549
550 cdma->running = false;
551 cdma->torndown = true;
552}
553
554void cdma_timeout_teardown_end(struct nvhost_cdma *cdma, u32 getptr)
555{
556 struct nvhost_master *dev = cdma_to_dev(cdma);
557 struct nvhost_channel *ch = cdma_to_channel(cdma);
558 u32 cmdproc_stop;
559
560 BUG_ON(!cdma->torndown || cdma->running);
561
562 dev_dbg(&dev->dev->dev,
563 "end channel teardown (id %d, DMAGET restart = 0x%x)\n",
564 ch->chid, getptr);
565
566 cmdproc_stop = readl(dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
567 cmdproc_stop &= ~(BIT(ch->chid));
568 writel(cmdproc_stop, dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
569
570 cdma->torndown = false;
571 cdma_timeout_restart(cdma, getptr);
572}
573
574/**
575 * If this timeout fires, it indicates the current sync_queue entry has
576 * exceeded its TTL and the userctx should be timed out and remaining
577 * submits already issued cleaned up (future submits return an error).
578 */
579static void cdma_timeout_handler(struct work_struct *work)
580{
581 struct nvhost_cdma *cdma;
582 struct nvhost_master *dev;
583 struct nvhost_syncpt *sp;
584 struct nvhost_channel *ch;
585
586 u32 syncpt_val;
587
588 u32 prev_cmdproc, cmdproc_stop;
589
590 cdma = container_of(to_delayed_work(work), struct nvhost_cdma,
591 timeout.wq);
592 dev = cdma_to_dev(cdma);
593 sp = &dev->syncpt;
594 ch = cdma_to_channel(cdma);
595
596 mutex_lock(&cdma->lock);
597
598 if (!cdma->timeout.clientid) {
599 dev_dbg(&dev->dev->dev,
600 "cdma_timeout: expired, but has no clientid\n");
601 mutex_unlock(&cdma->lock);
602 return;
603 }
604
605 /* stop processing to get a clean snapshot */
606 prev_cmdproc = readl(dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
607 cmdproc_stop = prev_cmdproc | BIT(ch->chid);
608 writel(cmdproc_stop, dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
609
610 dev_dbg(&dev->dev->dev, "cdma_timeout: cmdproc was 0x%x is 0x%x\n",
611 prev_cmdproc, cmdproc_stop);
612
613 syncpt_val = nvhost_syncpt_update_min(&dev->syncpt,
614 cdma->timeout.syncpt_id);
615
616 /* has buffer actually completed? */
617 if ((s32)(syncpt_val - cdma->timeout.syncpt_val) >= 0) {
618 dev_dbg(&dev->dev->dev,
619 "cdma_timeout: expired, but buffer had completed\n");
620 /* restore */
621 cmdproc_stop = prev_cmdproc & ~(BIT(ch->chid));
622 writel(cmdproc_stop,
623 dev->sync_aperture + HOST1X_SYNC_CMDPROC_STOP);
624 mutex_unlock(&cdma->lock);
625 return;
626 }
627
628 dev_warn(&dev->dev->dev,
629 "%s: timeout: %d (%s) ctx 0x%p, HW thresh %d, done %d\n",
630 __func__,
631 cdma->timeout.syncpt_id,
632 syncpt_op(sp).name(sp, cdma->timeout.syncpt_id),
633 cdma->timeout.ctx,
634 syncpt_val, cdma->timeout.syncpt_val);
635
636 /* stop HW, resetting channel/module */
637 cdma_op(cdma).timeout_teardown_begin(cdma);
638
639 nvhost_cdma_update_sync_queue(cdma, sp, &dev->dev->dev);
640 mutex_unlock(&cdma->lock);
641}
642
643int host1x_init_cdma_support(struct nvhost_master *host)
644{
645 host->op.cdma.start = cdma_start;
646 host->op.cdma.stop = cdma_stop;
647 host->op.cdma.kick = cdma_kick;
648
649 host->op.cdma.timeout_init = cdma_timeout_init;
650 host->op.cdma.timeout_destroy = cdma_timeout_destroy;
651 host->op.cdma.timeout_teardown_begin = cdma_timeout_teardown_begin;
652 host->op.cdma.timeout_teardown_end = cdma_timeout_teardown_end;
653 host->op.cdma.timeout_cpu_incr = cdma_timeout_cpu_incr;
654 host->op.cdma.timeout_pb_incr = cdma_timeout_pb_incr;
655
656 host->op.push_buffer.reset = push_buffer_reset;
657 host->op.push_buffer.init = push_buffer_init;
658 host->op.push_buffer.destroy = push_buffer_destroy;
659 host->op.push_buffer.push_to = push_buffer_push_to;
660 host->op.push_buffer.pop_from = push_buffer_pop_from;
661 host->op.push_buffer.space = push_buffer_space;
662 host->op.push_buffer.putptr = push_buffer_putptr;
663
664 return 0;
665}
diff --git a/drivers/video/tegra/host/host1x/host1x_cdma.h b/drivers/video/tegra/host/host1x/host1x_cdma.h
new file mode 100644
index 00000000000..60909236a7c
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_cdma.h
@@ -0,0 +1,41 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_cdma.h
3 *
4 * Tegra Graphics Host Channel
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_HOST1X_HOST1X_CDMA_H
22#define __NVHOST_HOST1X_HOST1X_CDMA_H
23
24/* Size of the sync queue. If it is too small, we won't be able to queue up
25 * many command buffers. If it is too large, we waste memory. */
26#define NVHOST_SYNC_QUEUE_SIZE 512
27
28/* Number of gathers we allow to be queued up per channel. Must be a
29 * power of two. Currently sized such that pushbuffer is 4KB (512*8B). */
30#define NVHOST_GATHER_QUEUE_SIZE 512
31
32/* 8 bytes per slot. (This number does not include the final RESTART.) */
33#define PUSH_BUFFER_SIZE (NVHOST_GATHER_QUEUE_SIZE * 8)
34
35/* 4K page containing GATHERed methods to increment channel syncpts
36 * and replaces the original timed out contexts GATHER slots */
37#define SYNCPT_INCR_BUFFER_SIZE_WORDS (4096 / sizeof(u32))
38
39int host1x_init_cdma_support(struct nvhost_master *);
40
41#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.c b/drivers/video/tegra/host/host1x/host1x_channel.c
new file mode 100644
index 00000000000..b16a34f416a
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_channel.c
@@ -0,0 +1,627 @@
1/*
2 * drivers/video/tegra/host/host1x/channel_host1x.c
3 *
4 * Tegra Graphics Host Channel
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_channel.h"
22#include "dev.h"
23#include "nvhost_hwctx.h"
24#include <trace/events/nvhost.h>
25#include <linux/slab.h>
26
27#include "host1x_syncpt.h"
28#include "host1x_channel.h"
29#include "host1x_hardware.h"
30#include "host1x_hwctx.h"
31#include "nvhost_intr.h"
32
33#define NV_FIFO_READ_TIMEOUT 200000
34
35static void sync_waitbases(struct nvhost_channel *ch, u32 syncpt_val)
36{
37 unsigned long waitbase;
38 unsigned long int waitbase_mask = ch->dev->waitbases;
39 if (ch->dev->waitbasesync) {
40 waitbase = find_first_bit(&waitbase_mask, BITS_PER_LONG);
41 nvhost_cdma_push(&ch->cdma,
42 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
43 NV_CLASS_HOST_LOAD_SYNCPT_BASE,
44 1),
45 nvhost_class_host_load_syncpt_base(waitbase,
46 syncpt_val));
47 }
48}
49
50static void *pre_submit_ctxsave(struct nvhost_job *job,
51 struct nvhost_hwctx *cur_ctx)
52{
53 struct nvhost_channel *ch = job->ch;
54 void *ctxsave_waiter = NULL;
55
56 /* Is a save needed? */
57 if (!cur_ctx || ch->cur_ctx == job->hwctx)
58 return NULL;
59
60 if (cur_ctx->has_timedout) {
61 dev_dbg(&ch->dev->dev,
62 "%s: skip save of timed out context (0x%p)\n",
63 __func__, ch->cur_ctx);
64
65 return NULL;
66 }
67
68 /* Allocate save waiter if needed */
69 if (ch->ctxhandler->save_service) {
70 ctxsave_waiter = nvhost_intr_alloc_waiter();
71 if (!ctxsave_waiter)
72 return ERR_PTR(-ENOMEM);
73 }
74
75 return ctxsave_waiter;
76}
77
78static void submit_ctxsave(struct nvhost_job *job, void *ctxsave_waiter,
79 struct nvhost_hwctx *cur_ctx)
80{
81 struct nvhost_master *host = nvhost_get_host(job->ch->dev);
82 struct nvhost_channel *ch = job->ch;
83 u32 syncval;
84 int err;
85 u32 save_thresh = 0;
86
87 /* Is a save needed? */
88 if (!cur_ctx || cur_ctx == job->hwctx || cur_ctx->has_timedout)
89 return;
90
91 /* Retrieve save threshold if we have a waiter */
92 if (ctxsave_waiter)
93 save_thresh =
94 nvhost_syncpt_read_max(&host->syncpt, job->syncpt_id)
95 + to_host1x_hwctx(cur_ctx)->save_thresh;
96
97 /* Adjust the syncpoint max */
98 job->syncpt_incrs += to_host1x_hwctx(cur_ctx)->save_incrs;
99 syncval = nvhost_syncpt_incr_max(&host->syncpt,
100 job->syncpt_id,
101 to_host1x_hwctx(cur_ctx)->save_incrs);
102
103 /* Send the save to channel */
104 cur_ctx->valid = true;
105 ch->ctxhandler->save_push(cur_ctx, &ch->cdma);
106 nvhost_job_get_hwctx(job, cur_ctx);
107
108 /* Notify save service */
109 if (ctxsave_waiter) {
110 err = nvhost_intr_add_action(&host->intr,
111 job->syncpt_id,
112 save_thresh,
113 NVHOST_INTR_ACTION_CTXSAVE, cur_ctx,
114 ctxsave_waiter,
115 NULL);
116 ctxsave_waiter = NULL;
117 WARN(err, "Failed to set ctx save interrupt");
118 }
119
120 trace_nvhost_channel_context_save(ch->dev->name, cur_ctx);
121}
122
123static void submit_ctxrestore(struct nvhost_job *job)
124{
125 struct nvhost_master *host = nvhost_get_host(job->ch->dev);
126 struct nvhost_channel *ch = job->ch;
127 u32 syncval;
128 struct host1x_hwctx *ctx =
129 job->hwctx ? to_host1x_hwctx(job->hwctx) : NULL;
130
131 /* First check if we have a valid context to restore */
132 if(ch->cur_ctx == job->hwctx || !job->hwctx || !job->hwctx->valid)
133 return;
134
135 /* Increment syncpt max */
136 job->syncpt_incrs += ctx->restore_incrs;
137 syncval = nvhost_syncpt_incr_max(&host->syncpt,
138 job->syncpt_id,
139 ctx->restore_incrs);
140
141 /* Send restore buffer to channel */
142 nvhost_cdma_push_gather(&ch->cdma,
143 host->nvmap,
144 nvmap_ref_to_handle(ctx->restore),
145 nvhost_opcode_gather(ctx->restore_size),
146 ctx->restore_phys);
147
148 trace_nvhost_channel_context_restore(ch->dev->name, &ctx->hwctx);
149}
150
151void submit_nullkickoff(struct nvhost_job *job, int user_syncpt_incrs)
152{
153 struct nvhost_channel *ch = job->ch;
154 int incr;
155 u32 op_incr;
156
157 /* push increments that correspond to nulled out commands */
158 op_incr = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
159 job->syncpt_id);
160 for (incr = 0; incr < (user_syncpt_incrs >> 1); incr++)
161 nvhost_cdma_push(&ch->cdma, op_incr, op_incr);
162 if (user_syncpt_incrs & 1)
163 nvhost_cdma_push(&ch->cdma, op_incr, NVHOST_OPCODE_NOOP);
164
165 /* for 3d, waitbase needs to be incremented after each submit */
166 if (ch->dev->class == NV_GRAPHICS_3D_CLASS_ID) {
167 u32 waitbase = to_host1x_hwctx_handler(job->hwctx->h)->waitbase;
168 nvhost_cdma_push(&ch->cdma,
169 nvhost_opcode_setclass(
170 NV_HOST1X_CLASS_ID,
171 NV_CLASS_HOST_INCR_SYNCPT_BASE,
172 1),
173 nvhost_class_host_incr_syncpt_base(
174 waitbase,
175 user_syncpt_incrs));
176 }
177}
178
179void submit_gathers(struct nvhost_job *job)
180{
181 /* push user gathers */
182 int i = 0;
183 for ( ; i < job->num_gathers; i++) {
184 u32 op1 = nvhost_opcode_gather(job->gathers[i].words);
185 u32 op2 = job->gathers[i].mem;
186 nvhost_cdma_push_gather(&job->ch->cdma,
187 job->nvmap, job->unpins[i/2],
188 op1, op2);
189 }
190}
191
192int host1x_channel_submit(struct nvhost_job *job)
193{
194 struct nvhost_channel *ch = job->ch;
195 struct nvhost_syncpt *sp = &nvhost_get_host(job->ch->dev)->syncpt;
196 u32 user_syncpt_incrs = job->syncpt_incrs;
197 u32 prev_max = 0;
198 u32 syncval;
199 int err;
200 void *completed_waiter = NULL, *ctxsave_waiter = NULL;
201
202 /* Bail out on timed out contexts */
203 if (job->hwctx && job->hwctx->has_timedout)
204 return -ETIMEDOUT;
205
206 /* Turn on the client module and host1x */
207 nvhost_module_busy(ch->dev);
208 if (ch->dev->busy)
209 ch->dev->busy(ch->dev);
210
211 /* before error checks, return current max */
212 prev_max = job->syncpt_end =
213 nvhost_syncpt_read_max(sp, job->syncpt_id);
214
215 /* get submit lock */
216 err = mutex_lock_interruptible(&ch->submitlock);
217 if (err) {
218 nvhost_module_idle(ch->dev);
219 goto error;
220 }
221
222 /* Do the needed allocations */
223 ctxsave_waiter = pre_submit_ctxsave(job, ch->cur_ctx);
224 if (IS_ERR(ctxsave_waiter)) {
225 err = PTR_ERR(ctxsave_waiter);
226 nvhost_module_idle(ch->dev);
227 mutex_unlock(&ch->submitlock);
228 goto error;
229 }
230
231 completed_waiter = nvhost_intr_alloc_waiter();
232 if (!completed_waiter) {
233 nvhost_module_idle(ch->dev);
234 mutex_unlock(&ch->submitlock);
235 err = -ENOMEM;
236 goto error;
237 }
238
239 /* remove stale waits */
240 if (job->num_waitchk) {
241 err = nvhost_syncpt_wait_check(sp,
242 job->nvmap,
243 job->waitchk_mask,
244 job->waitchk,
245 job->num_waitchk);
246 if (err) {
247 dev_warn(&ch->dev->dev,
248 "nvhost_syncpt_wait_check failed: %d\n", err);
249 mutex_unlock(&ch->submitlock);
250 nvhost_module_idle(ch->dev);
251 goto error;
252 }
253 }
254
255 /* begin a CDMA submit */
256 err = nvhost_cdma_begin(&ch->cdma, job);
257 if (err) {
258 mutex_unlock(&ch->submitlock);
259 nvhost_module_idle(ch->dev);
260 goto error;
261 }
262
263 submit_ctxsave(job, ctxsave_waiter, ch->cur_ctx);
264 submit_ctxrestore(job);
265 ch->cur_ctx = job->hwctx;
266
267 syncval = nvhost_syncpt_incr_max(sp,
268 job->syncpt_id, user_syncpt_incrs);
269
270 job->syncpt_end = syncval;
271
272 /* add a setclass for modules that require it */
273 if (ch->dev->class)
274 nvhost_cdma_push(&ch->cdma,
275 nvhost_opcode_setclass(ch->dev->class, 0, 0),
276 NVHOST_OPCODE_NOOP);
277
278 if (job->null_kickoff)
279 submit_nullkickoff(job, user_syncpt_incrs);
280 else
281 submit_gathers(job);
282
283 sync_waitbases(ch, job->syncpt_end);
284
285 /* end CDMA submit & stash pinned hMems into sync queue */
286 nvhost_cdma_end(&ch->cdma, job);
287
288 trace_nvhost_channel_submitted(ch->dev->name,
289 prev_max, syncval);
290
291 /* schedule a submit complete interrupt */
292 err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr,
293 job->syncpt_id, syncval,
294 NVHOST_INTR_ACTION_SUBMIT_COMPLETE, ch,
295 completed_waiter,
296 NULL);
297 completed_waiter = NULL;
298 WARN(err, "Failed to set submit complete interrupt");
299
300 mutex_unlock(&ch->submitlock);
301
302 return 0;
303
304error:
305 kfree(ctxsave_waiter);
306 kfree(completed_waiter);
307 return err;
308}
309
310int host1x_channel_read_3d_reg(
311 struct nvhost_channel *channel,
312 struct nvhost_hwctx *hwctx,
313 u32 offset,
314 u32 *value)
315{
316 struct host1x_hwctx *hwctx_to_save = NULL;
317 struct nvhost_hwctx_handler *h = hwctx->h;
318 struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
319 bool need_restore = false;
320 u32 syncpt_incrs = 4;
321 unsigned int pending = 0;
322 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
323 void *ref;
324 void *ctx_waiter, *read_waiter, *completed_waiter;
325 struct nvhost_job *job;
326 u32 syncval;
327 int err;
328
329 if (hwctx && hwctx->has_timedout)
330 return -ETIMEDOUT;
331
332 ctx_waiter = nvhost_intr_alloc_waiter();
333 read_waiter = nvhost_intr_alloc_waiter();
334 completed_waiter = nvhost_intr_alloc_waiter();
335 if (!ctx_waiter || !read_waiter || !completed_waiter) {
336 err = -ENOMEM;
337 goto done;
338 }
339
340 job = nvhost_job_alloc(channel, hwctx,
341 NULL,
342 nvhost_get_host(channel->dev)->nvmap, 0, 0);
343 if (!job) {
344 err = -ENOMEM;
345 goto done;
346 }
347
348 /* keep module powered */
349 nvhost_module_busy(channel->dev);
350
351 /* get submit lock */
352 err = mutex_lock_interruptible(&channel->submitlock);
353 if (err) {
354 nvhost_module_idle(channel->dev);
355 return err;
356 }
357
358 /* context switch */
359 if (channel->cur_ctx != hwctx) {
360 hwctx_to_save = channel->cur_ctx ?
361 to_host1x_hwctx(channel->cur_ctx) : NULL;
362 if (hwctx_to_save) {
363 syncpt_incrs += hwctx_to_save->save_incrs;
364 hwctx_to_save->hwctx.valid = true;
365 channel->ctxhandler->get(&hwctx_to_save->hwctx);
366 }
367 channel->cur_ctx = hwctx;
368 if (channel->cur_ctx && channel->cur_ctx->valid) {
369 need_restore = true;
370 syncpt_incrs += to_host1x_hwctx(channel->cur_ctx)
371 ->restore_incrs;
372 }
373 }
374
375 syncval = nvhost_syncpt_incr_max(&nvhost_get_host(channel->dev)->syncpt,
376 p->syncpt, syncpt_incrs);
377
378 job->syncpt_id = p->syncpt;
379 job->syncpt_incrs = syncpt_incrs;
380 job->syncpt_end = syncval;
381
382 /* begin a CDMA submit */
383 nvhost_cdma_begin(&channel->cdma, job);
384
385 /* push save buffer (pre-gather setup depends on unit) */
386 if (hwctx_to_save)
387 h->save_push(&hwctx_to_save->hwctx, &channel->cdma);
388
389 /* gather restore buffer */
390 if (need_restore)
391 nvhost_cdma_push(&channel->cdma,
392 nvhost_opcode_gather(to_host1x_hwctx(channel->cur_ctx)
393 ->restore_size),
394 to_host1x_hwctx(channel->cur_ctx)->restore_phys);
395
396 /* Switch to 3D - wait for it to complete what it was doing */
397 nvhost_cdma_push(&channel->cdma,
398 nvhost_opcode_setclass(NV_GRAPHICS_3D_CLASS_ID, 0, 0),
399 nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
400 p->syncpt));
401 nvhost_cdma_push(&channel->cdma,
402 nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
403 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
404 nvhost_class_host_wait_syncpt_base(p->syncpt,
405 p->waitbase, 1));
406 /* Tell 3D to send register value to FIFO */
407 nvhost_cdma_push(&channel->cdma,
408 nvhost_opcode_nonincr(NV_CLASS_HOST_INDOFF, 1),
409 nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_GR3D,
410 offset, false));
411 nvhost_cdma_push(&channel->cdma,
412 nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0),
413 NVHOST_OPCODE_NOOP);
414 /* Increment syncpt to indicate that FIFO can be read */
415 nvhost_cdma_push(&channel->cdma,
416 nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
417 p->syncpt),
418 NVHOST_OPCODE_NOOP);
419 /* Wait for value to be read from FIFO */
420 nvhost_cdma_push(&channel->cdma,
421 nvhost_opcode_nonincr(NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1),
422 nvhost_class_host_wait_syncpt_base(p->syncpt,
423 p->waitbase, 3));
424 /* Indicate submit complete */
425 nvhost_cdma_push(&channel->cdma,
426 nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1),
427 nvhost_class_host_incr_syncpt_base(p->waitbase, 4));
428 nvhost_cdma_push(&channel->cdma,
429 NVHOST_OPCODE_NOOP,
430 nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE,
431 p->syncpt));
432
433 /* end CDMA submit */
434 nvhost_cdma_end(&channel->cdma, job);
435 nvhost_job_put(job);
436 job = NULL;
437
438 /*
439 * schedule a context save interrupt (to drain the host FIFO
440 * if necessary, and to release the restore buffer)
441 */
442 if (hwctx_to_save) {
443 err = nvhost_intr_add_action(
444 &nvhost_get_host(channel->dev)->intr,
445 p->syncpt,
446 syncval - syncpt_incrs
447 + hwctx_to_save->save_incrs
448 - 1,
449 NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
450 ctx_waiter,
451 NULL);
452 ctx_waiter = NULL;
453 WARN(err, "Failed to set context save interrupt");
454 }
455
456 /* Wait for FIFO to be ready */
457 err = nvhost_intr_add_action(&nvhost_get_host(channel->dev)->intr,
458 p->syncpt, syncval - 2,
459 NVHOST_INTR_ACTION_WAKEUP, &wq,
460 read_waiter,
461 &ref);
462 read_waiter = NULL;
463 WARN(err, "Failed to set wakeup interrupt");
464 wait_event(wq,
465 nvhost_syncpt_is_expired(&nvhost_get_host(channel->dev)->syncpt,
466 p->syncpt, syncval - 2));
467 nvhost_intr_put_ref(&nvhost_get_host(channel->dev)->intr, ref);
468
469 /* Read the register value from FIFO */
470 err = host1x_drain_read_fifo(channel->aperture,
471 value, 1, &pending);
472
473 /* Indicate we've read the value */
474 nvhost_syncpt_cpu_incr(&nvhost_get_host(channel->dev)->syncpt,
475 p->syncpt);
476
477 /* Schedule a submit complete interrupt */
478 err = nvhost_intr_add_action(&nvhost_get_host(channel->dev)->intr,
479 p->syncpt, syncval,
480 NVHOST_INTR_ACTION_SUBMIT_COMPLETE, channel,
481 completed_waiter, NULL);
482 completed_waiter = NULL;
483 WARN(err, "Failed to set submit complete interrupt");
484
485 mutex_unlock(&channel->submitlock);
486
487done:
488 kfree(ctx_waiter);
489 kfree(read_waiter);
490 kfree(completed_waiter);
491 return err;
492}
493
494
495int host1x_drain_read_fifo(void __iomem *chan_regs,
496 u32 *ptr, unsigned int count, unsigned int *pending)
497{
498 unsigned int entries = *pending;
499 unsigned long timeout = jiffies + NV_FIFO_READ_TIMEOUT;
500 while (count) {
501 unsigned int num;
502
503 while (!entries && time_before(jiffies, timeout)) {
504 /* query host for number of entries in fifo */
505 entries = HOST1X_VAL(CHANNEL_FIFOSTAT, OUTFENTRIES,
506 readl(chan_regs + HOST1X_CHANNEL_FIFOSTAT));
507 if (!entries)
508 cpu_relax();
509 }
510
511 /* timeout -> return error */
512 if (!entries)
513 return -EIO;
514
515 num = min(entries, count);
516 entries -= num;
517 count -= num;
518
519 while (num & ~0x3) {
520 u32 arr[4];
521 arr[0] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
522 arr[1] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
523 arr[2] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
524 arr[3] = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
525 memcpy(ptr, arr, 4*sizeof(u32));
526 ptr += 4;
527 num -= 4;
528 }
529 while (num--)
530 *ptr++ = readl(chan_regs + HOST1X_CHANNEL_INDDATA);
531 }
532 *pending = entries;
533
534 return 0;
535}
536
537int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id)
538{
539 struct nvhost_channel *ch = dev->channel;
540 struct nvhost_hwctx *hwctx_to_save;
541 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
542 u32 syncpt_incrs, syncpt_val;
543 int err = 0;
544 void *ref;
545 void *ctx_waiter = NULL, *wakeup_waiter = NULL;
546 struct nvhost_job *job;
547
548 ctx_waiter = nvhost_intr_alloc_waiter();
549 wakeup_waiter = nvhost_intr_alloc_waiter();
550 if (!ctx_waiter || !wakeup_waiter) {
551 err = -ENOMEM;
552 goto done;
553 }
554
555 if (dev->busy)
556 dev->busy(dev);
557
558 mutex_lock(&ch->submitlock);
559 hwctx_to_save = ch->cur_ctx;
560 if (!hwctx_to_save) {
561 mutex_unlock(&ch->submitlock);
562 goto done;
563 }
564
565 job = nvhost_job_alloc(ch, hwctx_to_save,
566 NULL,
567 nvhost_get_host(ch->dev)->nvmap, 0, 0);
568 if (IS_ERR_OR_NULL(job)) {
569 err = PTR_ERR(job);
570 mutex_unlock(&ch->submitlock);
571 goto done;
572 }
573
574 hwctx_to_save->valid = true;
575 ch->ctxhandler->get(hwctx_to_save);
576 ch->cur_ctx = NULL;
577
578 syncpt_incrs = to_host1x_hwctx(hwctx_to_save)->save_incrs;
579 syncpt_val = nvhost_syncpt_incr_max(&nvhost_get_host(ch->dev)->syncpt,
580 syncpt_id, syncpt_incrs);
581
582 job->syncpt_id = syncpt_id;
583 job->syncpt_incrs = syncpt_incrs;
584 job->syncpt_end = syncpt_val;
585
586 err = nvhost_cdma_begin(&ch->cdma, job);
587 if (err) {
588 mutex_unlock(&ch->submitlock);
589 goto done;
590 }
591
592 ch->ctxhandler->save_push(hwctx_to_save, &ch->cdma);
593 nvhost_cdma_end(&ch->cdma, job);
594 nvhost_job_put(job);
595 job = NULL;
596
597 err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr, syncpt_id,
598 syncpt_val - syncpt_incrs +
599 to_host1x_hwctx(hwctx_to_save)->save_thresh,
600 NVHOST_INTR_ACTION_CTXSAVE, hwctx_to_save,
601 ctx_waiter,
602 NULL);
603 ctx_waiter = NULL;
604 WARN(err, "Failed to set context save interrupt");
605
606 err = nvhost_intr_add_action(&nvhost_get_host(ch->dev)->intr,
607 syncpt_id, syncpt_val,
608 NVHOST_INTR_ACTION_WAKEUP, &wq,
609 wakeup_waiter,
610 &ref);
611 wakeup_waiter = NULL;
612 WARN(err, "Failed to set wakeup interrupt");
613 wait_event(wq,
614 nvhost_syncpt_is_expired(&nvhost_get_host(ch->dev)->syncpt,
615 syncpt_id, syncpt_val));
616
617 nvhost_intr_put_ref(&nvhost_get_host(ch->dev)->intr, ref);
618
619 nvhost_cdma_update(&ch->cdma);
620
621 mutex_unlock(&ch->submitlock);
622
623done:
624 kfree(ctx_waiter);
625 kfree(wakeup_waiter);
626 return err;
627}
diff --git a/drivers/video/tegra/host/host1x/host1x_channel.h b/drivers/video/tegra/host/host1x/host1x_channel.h
new file mode 100644
index 00000000000..4113dbcada2
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_channel.h
@@ -0,0 +1,45 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_channel.h
3 *
4 * Tegra Graphics Host Channel
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_HOST1X_CHANNEL_H
22#define __NVHOST_HOST1X_CHANNEL_H
23
24struct nvhost_job;
25struct nvhost_channel;
26struct nvhost_hwctx;
27struct nvhost_device;
28
29/* Submit job to a host1x client */
30int host1x_channel_submit(struct nvhost_job *job);
31
32/* Read 3d register via FIFO */
33int host1x_channel_read_3d_reg(
34 struct nvhost_channel *channel,
35 struct nvhost_hwctx *hwctx,
36 u32 offset,
37 u32 *value);
38
39/* Reads words from FIFO */
40int host1x_drain_read_fifo(void __iomem *chan_regs,
41 u32 *ptr, unsigned int count, unsigned int *pending);
42
43int host1x_save_context(struct nvhost_device *dev, u32 syncpt_id);
44
45#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_debug.c b/drivers/video/tegra/host/host1x/host1x_debug.c
new file mode 100644
index 00000000000..1a1d764bbd6
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_debug.c
@@ -0,0 +1,404 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_debug.c
3 *
4 * Copyright (C) 2010 Google, Inc.
5 * Author: Erik Gilling <konkers@android.com>
6 *
7 * Copyright (C) 2011 NVIDIA Corporation
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/debugfs.h>
21#include <linux/seq_file.h>
22#include <linux/mm.h>
23
24#include <linux/io.h>
25
26#include "dev.h"
27#include "debug.h"
28#include "nvhost_cdma.h"
29#include "../../nvmap/nvmap.h"
30
31#include "host1x_hardware.h"
32#include "host1x_cdma.h"
33
34#define NVHOST_DEBUG_MAX_PAGE_OFFSET 102400
35
36enum {
37 NVHOST_DBG_STATE_CMD = 0,
38 NVHOST_DBG_STATE_DATA = 1,
39 NVHOST_DBG_STATE_GATHER = 2
40};
41
42static int show_channel_command(struct output *o, u32 addr, u32 val, int *count)
43{
44 unsigned mask;
45 unsigned subop;
46
47 switch (val >> 28) {
48 case 0x0:
49 mask = val & 0x3f;
50 if (mask) {
51 nvhost_debug_output(o,
52 "SETCL(class=%03x, offset=%03x, mask=%02x, [",
53 val >> 6 & 0x3ff, val >> 16 & 0xfff, mask);
54 *count = hweight8(mask);
55 return NVHOST_DBG_STATE_DATA;
56 } else {
57 nvhost_debug_output(o, "SETCL(class=%03x)\n",
58 val >> 6 & 0x3ff);
59 return NVHOST_DBG_STATE_CMD;
60 }
61
62 case 0x1:
63 nvhost_debug_output(o, "INCR(offset=%03x, [",
64 val >> 16 & 0xfff);
65 *count = val & 0xffff;
66 return NVHOST_DBG_STATE_DATA;
67
68 case 0x2:
69 nvhost_debug_output(o, "NONINCR(offset=%03x, [",
70 val >> 16 & 0xfff);
71 *count = val & 0xffff;
72 return NVHOST_DBG_STATE_DATA;
73
74 case 0x3:
75 mask = val & 0xffff;
76 nvhost_debug_output(o, "MASK(offset=%03x, mask=%03x, [",
77 val >> 16 & 0xfff, mask);
78 *count = hweight16(mask);
79 return NVHOST_DBG_STATE_DATA;
80
81 case 0x4:
82 nvhost_debug_output(o, "IMM(offset=%03x, data=%03x)\n",
83 val >> 16 & 0xfff, val & 0xffff);
84 return NVHOST_DBG_STATE_CMD;
85
86 case 0x5:
87 nvhost_debug_output(o, "RESTART(offset=%08x)\n", val << 4);
88 return NVHOST_DBG_STATE_CMD;
89
90 case 0x6:
91 nvhost_debug_output(o, "GATHER(offset=%03x, insert=%d, type=%d, count=%04x, addr=[",
92 val >> 16 & 0xfff, val >> 15 & 0x1, val >> 14 & 0x1,
93 val & 0x3fff);
94 *count = val & 0x3fff; /* TODO: insert */
95 return NVHOST_DBG_STATE_GATHER;
96
97 case 0xe:
98 subop = val >> 24 & 0xf;
99 if (subop == 0)
100 nvhost_debug_output(o, "ACQUIRE_MLOCK(index=%d)\n",
101 val & 0xff);
102 else if (subop == 1)
103 nvhost_debug_output(o, "RELEASE_MLOCK(index=%d)\n",
104 val & 0xff);
105 else
106 nvhost_debug_output(o, "EXTEND_UNKNOWN(%08x)\n", val);
107 return NVHOST_DBG_STATE_CMD;
108
109 default:
110 return NVHOST_DBG_STATE_CMD;
111 }
112}
113
114static void show_channel_gather(struct output *o, u32 addr,
115 phys_addr_t phys_addr, u32 words, struct nvhost_cdma *cdma);
116
117static void show_channel_word(struct output *o, int *state, int *count,
118 u32 addr, u32 val, struct nvhost_cdma *cdma)
119{
120 static int start_count, dont_print;
121
122 switch (*state) {
123 case NVHOST_DBG_STATE_CMD:
124 if (addr)
125 nvhost_debug_output(o, "%08x: %08x:", addr, val);
126 else
127 nvhost_debug_output(o, "%08x:", val);
128
129 *state = show_channel_command(o, addr, val, count);
130 dont_print = 0;
131 start_count = *count;
132 if (*state == NVHOST_DBG_STATE_DATA && *count == 0) {
133 *state = NVHOST_DBG_STATE_CMD;
134 nvhost_debug_output(o, "])\n");
135 }
136 break;
137
138 case NVHOST_DBG_STATE_DATA:
139 (*count)--;
140 if (start_count - *count < 64)
141 nvhost_debug_output(o, "%08x%s",
142 val, *count > 0 ? ", " : "])\n");
143 else if (!dont_print && (*count > 0)) {
144 nvhost_debug_output(o, "[truncated; %d more words]\n",
145 *count);
146 dont_print = 1;
147 }
148 if (*count == 0)
149 *state = NVHOST_DBG_STATE_CMD;
150 break;
151
152 case NVHOST_DBG_STATE_GATHER:
153 *state = NVHOST_DBG_STATE_CMD;
154 nvhost_debug_output(o, "%08x]):\n", val);
155 if (cdma) {
156 show_channel_gather(o, addr, val,
157 *count, cdma);
158 }
159 break;
160 }
161}
162
163static void show_channel_gather(struct output *o, u32 addr,
164 phys_addr_t phys_addr,
165 u32 words, struct nvhost_cdma *cdma)
166{
167#if defined(CONFIG_TEGRA_NVMAP)
168 /* Map dmaget cursor to corresponding nvmap_handle */
169 struct push_buffer *pb = &cdma->push_buffer;
170 u32 cur = addr - pb->phys;
171 struct nvmap_client_handle *nvmap = &pb->nvmap[cur/8];
172 struct nvmap_handle_ref ref;
173 u32 *map_addr, offset;
174 phys_addr_t pin_addr;
175 int state, count, i;
176
177 if ((u32)nvmap->handle == NVHOST_CDMA_PUSH_GATHER_CTXSAVE) {
178 nvhost_debug_output(o, "[context save]\n");
179 return;
180 }
181
182 if (!nvmap->handle || !nvmap->client
183 || atomic_read(&nvmap->handle->ref) < 1) {
184 nvhost_debug_output(o, "[already deallocated]\n");
185 return;
186 }
187
188 /* Create a fake nvmap_handle_ref - nvmap requires it
189 * but accesses only the first field - nvmap_handle */
190 ref.handle = nvmap->handle;
191
192 map_addr = nvmap_mmap(&ref);
193 if (!map_addr) {
194 nvhost_debug_output(o, "[could not mmap]\n");
195 return;
196 }
197
198 /* Get base address from nvmap */
199 pin_addr = nvmap_pin(nvmap->client, &ref);
200 if (IS_ERR_VALUE(pin_addr)) {
201 nvhost_debug_output(o, "[couldn't pin]\n");
202 nvmap_munmap(&ref, map_addr);
203 return;
204 }
205
206 offset = phys_addr - pin_addr;
207 /*
208 * Sometimes we're given different hardware address to the same
209 * page - in these cases the offset will get an invalid number and
210 * we just have to bail out.
211 */
212 if (offset > NVHOST_DEBUG_MAX_PAGE_OFFSET) {
213 nvhost_debug_output(o, "[address mismatch]\n");
214 } else {
215 /* GATHER buffer starts always with commands */
216 state = NVHOST_DBG_STATE_CMD;
217 for (i = 0; i < words; i++)
218 show_channel_word(o, &state, &count,
219 phys_addr + i * 4,
220 *(map_addr + offset/4 + i),
221 cdma);
222 }
223 nvmap_unpin(nvmap->client, &ref);
224 nvmap_munmap(&ref, map_addr);
225#endif
226}
227
228static void show_channel_pair(struct output *o, u32 addr,
229 u32 w0, u32 w1, struct nvhost_cdma *cdma)
230{
231 int state = NVHOST_DBG_STATE_CMD;
232 int count;
233
234 show_channel_word(o, &state, &count, addr, w0, cdma);
235 show_channel_word(o, &state, &count, addr+4, w1, cdma);
236}
237
238/**
239 * Retrieve the op pair at a slot offset from a DMA address
240 */
241static void cdma_peek(struct nvhost_cdma *cdma,
242 u32 dmaget, int slot, u32 *out)
243{
244 u32 offset = dmaget - cdma->push_buffer.phys;
245 u32 *p = cdma->push_buffer.mapped;
246
247 offset = ((offset + slot * 8) & (PUSH_BUFFER_SIZE - 1)) >> 2;
248 out[0] = p[offset];
249 out[1] = p[offset + 1];
250}
251
252u32 previous_oppair(struct nvhost_cdma *cdma, u32 cur)
253{
254 u32 pb = cdma->push_buffer.phys;
255 u32 prev = cur-8;
256 if (prev < pb)
257 prev += PUSH_BUFFER_SIZE;
258 return prev;
259}
260
261static void t20_debug_show_channel_cdma(struct nvhost_master *m,
262 struct nvhost_channel *ch, struct output *o, int chid)
263{
264 struct nvhost_channel *channel = ch;
265 struct nvhost_cdma *cdma = &channel->cdma;
266 u32 dmaput, dmaget, dmactrl;
267 u32 cbstat, cbread;
268 u32 val, base, baseval;
269 u32 pbw[2];
270
271 dmaput = readl(channel->aperture + HOST1X_CHANNEL_DMAPUT);
272 dmaget = readl(channel->aperture + HOST1X_CHANNEL_DMAGET);
273 dmactrl = readl(channel->aperture + HOST1X_CHANNEL_DMACTRL);
274 cbread = readl(m->sync_aperture + HOST1X_SYNC_CBREAD_x(chid));
275 cbstat = readl(m->sync_aperture + HOST1X_SYNC_CBSTAT_x(chid));
276
277 nvhost_debug_output(o, "%d-%s (%d): ", chid,
278 channel->dev->name,
279 channel->dev->refcount);
280
281 if (HOST1X_VAL(CHANNEL_DMACTRL, DMASTOP, dmactrl)
282 || !channel->cdma.push_buffer.mapped) {
283 nvhost_debug_output(o, "inactive\n\n");
284 return;
285 }
286
287 switch (cbstat) {
288 case 0x00010008:
289 nvhost_debug_output(o, "waiting on syncpt %d val %d\n",
290 cbread >> 24, cbread & 0xffffff);
291 break;
292
293 case 0x00010009:
294 base = (cbread >> 16) & 0xff;
295 val = readl(m->sync_aperture +
296 HOST1X_SYNC_SYNCPT_BASE_x(base));
297 baseval = HOST1X_VAL(SYNC_SYNCPT_BASE_0, BASE, val);
298 val = cbread & 0xffff;
299 nvhost_debug_output(o, "waiting on syncpt %d val %d "
300 "(base %d = %d; offset = %d)\n",
301 cbread >> 24, baseval + val,
302 base, baseval, val);
303 break;
304
305 default:
306 nvhost_debug_output(o,
307 "active class %02x, offset %04x, val %08x\n",
308 HOST1X_VAL(SYNC_CBSTAT_0, CBCLASS0, cbstat),
309 HOST1X_VAL(SYNC_CBSTAT_0, CBOFFSET0, cbstat),
310 cbread);
311 break;
312 }
313
314 nvhost_debug_output(o, "DMAPUT %08x, DMAGET %08x, DMACTL %08x\n",
315 dmaput, dmaget, dmactrl);
316 nvhost_debug_output(o, "CBREAD %08x, CBSTAT %08x\n", cbread, cbstat);
317
318 cdma_peek(cdma, dmaget, -1, pbw);
319 show_channel_pair(o, previous_oppair(cdma, dmaget),
320 pbw[0], pbw[1], &channel->cdma);
321 nvhost_debug_output(o, "\n");
322}
323
324void t20_debug_show_channel_fifo(struct nvhost_master *m,
325 struct nvhost_channel *ch, struct output *o, int chid)
326{
327 u32 val, rd_ptr, wr_ptr, start, end;
328 struct nvhost_channel *channel = ch;
329 int state, count;
330
331 nvhost_debug_output(o, "%d: fifo:\n", chid);
332
333 val = readl(channel->aperture + HOST1X_CHANNEL_FIFOSTAT);
334 nvhost_debug_output(o, "FIFOSTAT %08x\n", val);
335 if (HOST1X_VAL(CHANNEL_FIFOSTAT, CFEMPTY, val)) {
336 nvhost_debug_output(o, "[empty]\n");
337 return;
338 }
339
340 writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
341 writel(HOST1X_CREATE(SYNC_CFPEEK_CTRL, ENA, 1)
342 | HOST1X_CREATE(SYNC_CFPEEK_CTRL, CHANNR, chid),
343 m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
344
345 val = readl(m->sync_aperture + HOST1X_SYNC_CFPEEK_PTRS);
346 rd_ptr = HOST1X_VAL(SYNC_CFPEEK_PTRS, CF_RD_PTR, val);
347 wr_ptr = HOST1X_VAL(SYNC_CFPEEK_PTRS, CF_WR_PTR, val);
348
349 val = readl(m->sync_aperture + HOST1X_SYNC_CFx_SETUP(chid));
350 start = HOST1X_VAL(SYNC_CF0_SETUP, BASE, val);
351 end = HOST1X_VAL(SYNC_CF0_SETUP, LIMIT, val);
352
353 state = NVHOST_DBG_STATE_CMD;
354
355 do {
356 writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
357 writel(HOST1X_CREATE(SYNC_CFPEEK_CTRL, ENA, 1)
358 | HOST1X_CREATE(SYNC_CFPEEK_CTRL, CHANNR, chid)
359 | HOST1X_CREATE(SYNC_CFPEEK_CTRL, ADDR, rd_ptr),
360 m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
361 val = readl(m->sync_aperture + HOST1X_SYNC_CFPEEK_READ);
362
363 show_channel_word(o, &state, &count, 0, val, NULL);
364
365 if (rd_ptr == end)
366 rd_ptr = start;
367 else
368 rd_ptr++;
369 } while (rd_ptr != wr_ptr);
370
371 if (state == NVHOST_DBG_STATE_DATA)
372 nvhost_debug_output(o, ", ...])\n");
373 nvhost_debug_output(o, "\n");
374
375 writel(0x0, m->sync_aperture + HOST1X_SYNC_CFPEEK_CTRL);
376}
377
378static void t20_debug_show_mlocks(struct nvhost_master *m, struct output *o)
379{
380 u32 __iomem *mlo_regs = m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0;
381 int i;
382
383 nvhost_debug_output(o, "---- mlocks ----\n");
384 for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
385 u32 owner = readl(mlo_regs + i);
386 if (HOST1X_VAL(SYNC_MLOCK_OWNER_0, CH_OWNS, owner))
387 nvhost_debug_output(o, "%d: locked by channel %d\n",
388 i, HOST1X_VAL(SYNC_MLOCK_OWNER_0, CHID, owner));
389 else if (HOST1X_VAL(SYNC_MLOCK_OWNER_0, CPU_OWNS, owner))
390 nvhost_debug_output(o, "%d: locked by cpu\n", i);
391 else
392 nvhost_debug_output(o, "%d: unlocked\n", i);
393 }
394 nvhost_debug_output(o, "\n");
395}
396
397int nvhost_init_t20_debug_support(struct nvhost_master *host)
398{
399 host->op.debug.show_channel_cdma = t20_debug_show_channel_cdma;
400 host->op.debug.show_channel_fifo = t20_debug_show_channel_fifo;
401 host->op.debug.show_mlocks = t20_debug_show_mlocks;
402
403 return 0;
404}
diff --git a/drivers/video/tegra/host/host1x/host1x_hardware.h b/drivers/video/tegra/host/host1x/host1x_hardware.h
new file mode 100644
index 00000000000..d13d5752364
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_hardware.h
@@ -0,0 +1,274 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_hardware.h
3 *
4 * Tegra Graphics Host Register Offsets
5 *
6 * Copyright (c) 2010-2012 NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_HOST1X_HOST1X_HARDWARE_H
22#define __NVHOST_HOST1X_HOST1X_HARDWARE_H
23
24#include <linux/types.h>
25#include <linux/bitops.h>
26
27/* class ids */
28enum {
29 NV_HOST1X_CLASS_ID = 0x1,
30 NV_VIDEO_ENCODE_MPEG_CLASS_ID = 0x20,
31 NV_GRAPHICS_3D_CLASS_ID = 0x60
32};
33
34
35/* channel registers */
36#define NV_HOST1X_CHANNELS 8
37#define NV_HOST1X_CHANNEL0_BASE 0
38#define NV_HOST1X_CHANNEL_MAP_SIZE_BYTES 16384
39#define NV_HOST1X_SYNC_MLOCK_NUM 16
40
41#define HOST1X_VAL(reg, field, regdata) \
42 ((regdata >> HOST1X_##reg##_##field##_SHIFT) \
43 & HOST1X_##reg##_##field##_MASK)
44#define HOST1X_CREATE(reg, field, data) \
45 ((data & HOST1X_##reg##_##field##_MASK) \
46 << HOST1X_##reg##_##field##_SHIFT) \
47
48#define HOST1X_CHANNEL_FIFOSTAT 0x00
49#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_SHIFT 10
50#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_MASK 0x1
51#define HOST1X_CHANNEL_FIFOSTAT_OUTFENTRIES_SHIFT 24
52#define HOST1X_CHANNEL_FIFOSTAT_OUTFENTRIES_MASK 0x1f
53#define HOST1X_CHANNEL_INDDATA 0x0c
54#define HOST1X_CHANNEL_DMASTART 0x14
55#define HOST1X_CHANNEL_DMAPUT 0x18
56#define HOST1X_CHANNEL_DMAGET 0x1c
57#define HOST1X_CHANNEL_DMAEND 0x20
58#define HOST1X_CHANNEL_DMACTRL 0x24
59#define HOST1X_CHANNEL_DMACTRL_DMASTOP_SHIFT 0
60#define HOST1X_CHANNEL_DMACTRL_DMASTOP_MASK 0x1
61#define HOST1X_CHANNEL_DMACTRL_DMAGETRST_SHIFT 1
62#define HOST1X_CHANNEL_DMACTRL_DMAGETRST_MASK 0x1
63#define HOST1X_CHANNEL_DMACTRL_DMAINITGET_SHIFT 2
64#define HOST1X_CHANNEL_DMACTRL_DMAINITGET_MASK 0x1
65
66#define HOST1X_CHANNEL_SYNC_REG_BASE 0x3000
67
68#define HOST1X_SYNC_INTMASK 0x4
69#define HOST1X_SYNC_INTC0MASK 0x8
70#define HOST1X_SYNC_HINTSTATUS 0x20
71#define HOST1X_SYNC_HINTMASK 0x24
72#define HOST1X_SYNC_HINTSTATUS_EXT 0x28
73#define HOST1X_SYNC_HINTSTATUS_EXT_IP_READ_INT_SHIFT 30
74#define HOST1X_SYNC_HINTSTATUS_EXT_IP_READ_INT_MASK 0x1
75#define HOST1X_SYNC_HINTSTATUS_EXT_IP_WRITE_INT_SHIFT 31
76#define HOST1X_SYNC_HINTSTATUS_EXT_IP_WRITE_INT_MASK 0x1
77#define HOST1X_SYNC_HINTMASK_EXT 0x2c
78#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS 0x40
79#define HOST1X_SYNC_SYNCPT_THRESH_CPU1_INT_STATUS 0x48
80#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE 0x60
81#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0 0x68
82#define HOST1X_SYNC_CF0_SETUP 0x80
83#define HOST1X_SYNC_CF0_SETUP_BASE_SHIFT 0
84#define HOST1X_SYNC_CF0_SETUP_BASE_MASK 0x1ff
85#define HOST1X_SYNC_CF0_SETUP_LIMIT_SHIFT 16
86#define HOST1X_SYNC_CF0_SETUP_LIMIT_MASK 0x1ff
87#define HOST1X_SYNC_CFx_SETUP(x) (HOST1X_SYNC_CF0_SETUP + (4 * (x)))
88
89#define HOST1X_SYNC_CMDPROC_STOP 0xac
90#define HOST1X_SYNC_CH_TEARDOWN 0xb0
91#define HOST1X_SYNC_USEC_CLK 0x1a4
92#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG 0x1a8
93#define HOST1X_SYNC_IP_BUSY_TIMEOUT 0x1bc
94#define HOST1X_SYNC_IP_READ_TIMEOUT_ADDR 0x1c0
95#define HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR 0x1c4
96#define HOST1X_SYNC_MLOCK_0 0x2c0
97#define HOST1X_SYNC_MLOCK_OWNER_0 0x340
98#define HOST1X_SYNC_MLOCK_OWNER_0_CHID_SHIFT 8
99#define HOST1X_SYNC_MLOCK_OWNER_0_CHID_MASK 0xf
100#define HOST1X_SYNC_MLOCK_OWNER_0_CPU_OWNS_SHIFT 1
101#define HOST1X_SYNC_MLOCK_OWNER_0_CPU_OWNS_MASK 0x1
102#define HOST1X_SYNC_MLOCK_OWNER_0_CH_OWNS_SHIFT 0
103#define HOST1X_SYNC_MLOCK_OWNER_0_CH_OWNS_MASK 0x1
104#define HOST1X_SYNC_SYNCPT_0 0x400
105#define HOST1X_SYNC_SYNCPT_INT_THRESH_0 0x500
106
107#define HOST1X_SYNC_SYNCPT_BASE_0 0x600
108#define HOST1X_SYNC_SYNCPT_BASE_0_BASE_SHIFT 0
109#define HOST1X_SYNC_SYNCPT_BASE_0_BASE_MASK 0xffff
110#define HOST1X_SYNC_SYNCPT_BASE_x(x) (HOST1X_SYNC_SYNCPT_BASE_0 + (4 * (x)))
111
112#define HOST1X_SYNC_SYNCPT_CPU_INCR 0x700
113
114#define HOST1X_SYNC_CBREAD_0 0x720
115#define HOST1X_SYNC_CBREAD_x(x) (HOST1X_SYNC_CBREAD_0 + (4 * (x)))
116#define HOST1X_SYNC_CFPEEK_CTRL 0x74c
117#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_SHIFT 0
118#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_MASK 0x1ff
119#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_SHIFT 16
120#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_MASK 0x7
121#define HOST1X_SYNC_CFPEEK_CTRL_ENA_SHIFT 31
122#define HOST1X_SYNC_CFPEEK_CTRL_ENA_MASK 0x1
123#define HOST1X_SYNC_CFPEEK_READ 0x750
124#define HOST1X_SYNC_CFPEEK_PTRS 0x754
125#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_SHIFT 0
126#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_MASK 0x1ff
127#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_SHIFT 16
128#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_MASK 0x1ff
129#define HOST1X_SYNC_CBSTAT_0 0x758
130#define HOST1X_SYNC_CBSTAT_0_CBOFFSET0_SHIFT 0
131#define HOST1X_SYNC_CBSTAT_0_CBOFFSET0_MASK 0xffff
132#define HOST1X_SYNC_CBSTAT_0_CBCLASS0_SHIFT 16
133#define HOST1X_SYNC_CBSTAT_0_CBCLASS0_MASK 0xffff
134#define HOST1X_SYNC_CBSTAT_x(x) (HOST1X_SYNC_CBSTAT_0 + (4 * (x)))
135
136/* sync registers */
137#define NV_HOST1X_SYNCPT_NB_PTS 32
138#define NV_HOST1X_SYNCPT_NB_BASES 8
139#define NV_HOST1X_NB_MLOCKS 16
140
141/* host class methods */
142enum {
143 NV_CLASS_HOST_INCR_SYNCPT = 0x0,
144 NV_CLASS_HOST_WAIT_SYNCPT = 0x8,
145 NV_CLASS_HOST_WAIT_SYNCPT_BASE = 0x9,
146 NV_CLASS_HOST_LOAD_SYNCPT_BASE = 0xb,
147 NV_CLASS_HOST_INCR_SYNCPT_BASE = 0xc,
148 NV_CLASS_HOST_INDOFF = 0x2d,
149 NV_CLASS_HOST_INDDATA = 0x2e
150};
151/* sync point conditionals */
152enum {
153 NV_SYNCPT_IMMEDIATE = 0x0,
154 NV_SYNCPT_OP_DONE = 0x1,
155 NV_SYNCPT_RD_DONE = 0x2,
156 NV_SYNCPT_REG_WR_SAFE = 0x3,
157};
158
159static inline u32 nvhost_class_host_wait_syncpt(
160 unsigned indx, unsigned threshold)
161{
162 return (indx << 24) | (threshold & 0xffffff);
163}
164
165static inline u32 nvhost_class_host_load_syncpt_base(
166 unsigned indx, unsigned threshold)
167{
168 return (indx << 24) | (threshold & 0xffffff);
169}
170
171static inline u32 nvhost_class_host_wait_syncpt_base(
172 unsigned indx, unsigned base_indx, unsigned offset)
173{
174 return (indx << 24) | (base_indx << 16) | offset;
175}
176
177static inline u32 nvhost_class_host_incr_syncpt_base(
178 unsigned base_indx, unsigned offset)
179{
180 return (base_indx << 24) | offset;
181}
182
183static inline u32 nvhost_class_host_incr_syncpt(
184 unsigned cond, unsigned indx)
185{
186 return (cond << 8) | indx;
187}
188
189enum {
190 NV_HOST_MODULE_HOST1X = 0,
191 NV_HOST_MODULE_MPE = 1,
192 NV_HOST_MODULE_GR3D = 6
193};
194
195static inline u32 nvhost_class_host_indoff_reg_write(
196 unsigned mod_id, unsigned offset, bool auto_inc)
197{
198 u32 v = (0xf << 28) | (mod_id << 18) | (offset << 2);
199 if (auto_inc)
200 v |= BIT(27);
201 return v;
202}
203
204static inline u32 nvhost_class_host_indoff_reg_read(
205 unsigned mod_id, unsigned offset, bool auto_inc)
206{
207 u32 v = (mod_id << 18) | (offset << 2) | 1;
208 if (auto_inc)
209 v |= BIT(27);
210 return v;
211}
212
213
214/* cdma opcodes */
215static inline u32 nvhost_opcode_setclass(
216 unsigned class_id, unsigned offset, unsigned mask)
217{
218 return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
219}
220
221static inline u32 nvhost_opcode_incr(unsigned offset, unsigned count)
222{
223 return (1 << 28) | (offset << 16) | count;
224}
225
226static inline u32 nvhost_opcode_nonincr(unsigned offset, unsigned count)
227{
228 return (2 << 28) | (offset << 16) | count;
229}
230
231static inline u32 nvhost_opcode_mask(unsigned offset, unsigned mask)
232{
233 return (3 << 28) | (offset << 16) | mask;
234}
235
236static inline u32 nvhost_opcode_imm(unsigned offset, unsigned value)
237{
238 return (4 << 28) | (offset << 16) | value;
239}
240
241static inline u32 nvhost_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
242{
243 return nvhost_opcode_imm(NV_CLASS_HOST_INCR_SYNCPT,
244 nvhost_class_host_incr_syncpt(cond, indx));
245}
246
247static inline u32 nvhost_opcode_restart(unsigned address)
248{
249 return (5 << 28) | (address >> 4);
250}
251
252static inline u32 nvhost_opcode_gather(unsigned count)
253{
254 return (6 << 28) | count;
255}
256
257static inline u32 nvhost_opcode_gather_nonincr(unsigned offset, unsigned count)
258{
259 return (6 << 28) | (offset << 16) | BIT(15) | count;
260}
261
262static inline u32 nvhost_opcode_gather_incr(unsigned offset, unsigned count)
263{
264 return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
265}
266
267#define NVHOST_OPCODE_NOOP nvhost_opcode_nonincr(0, 0)
268
269static inline u32 nvhost_mask2(unsigned x, unsigned y)
270{
271 return 1 | (1 << (y - x));
272}
273
274#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_hwctx.h b/drivers/video/tegra/host/host1x/host1x_hwctx.h
new file mode 100644
index 00000000000..7587642d0e1
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_hwctx.h
@@ -0,0 +1,65 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_hwctx.h
3 *
4 * Tegra Graphics Host HOST1X Hardware Context Interface
5 *
6 * Copyright (c) 2012, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef __NVHOST_HOST1X_HWCTX_H
24#define __NVHOST_HOST1X_HWCTX_H
25
26#include <linux/kref.h>
27
28struct nvhost_hwctx_handler;
29struct nvhost_channel;
30
31#define to_host1x_hwctx_handler(handler) \
32 container_of((handler), struct host1x_hwctx_handler, h)
33#define to_host1x_hwctx(h) container_of((h), struct host1x_hwctx, hwctx)
34#define host1x_hwctx_handler(_hwctx) to_host1x_hwctx_handler((_hwctx)->hwctx.h)
35
36struct host1x_hwctx {
37 struct nvhost_hwctx hwctx;
38
39 u32 save_incrs;
40 u32 save_thresh;
41 u32 save_slots;
42
43 struct nvmap_handle_ref *restore;
44 u32 *restore_virt;
45 phys_addr_t restore_phys;
46 u32 restore_size;
47 u32 restore_incrs;
48};
49
50struct host1x_hwctx_handler {
51 struct nvhost_hwctx_handler h;
52
53 u32 syncpt;
54 u32 waitbase;
55 u32 restore_size;
56 u32 restore_incrs;
57 struct nvmap_handle_ref *save_buf;
58 u32 save_incrs;
59 u32 save_thresh;
60 u32 save_slots;
61 phys_addr_t save_phys;
62 u32 save_size;
63};
64
65#endif
diff --git a/drivers/video/tegra/host/host1x/host1x_intr.c b/drivers/video/tegra/host/host1x/host1x_intr.c
new file mode 100644
index 00000000000..47e984e2943
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_intr.c
@@ -0,0 +1,218 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_intr.c
3 *
4 * Tegra Graphics Host Interrupt Management
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/interrupt.h>
22#include <linux/irq.h>
23
24#include "nvhost_intr.h"
25#include "dev.h"
26#include "host1x_hardware.h"
27
28
29/*** HW host sync management ***/
30
31static void t20_intr_init_host_sync(struct nvhost_intr *intr)
32{
33 struct nvhost_master *dev = intr_to_dev(intr);
34 void __iomem *sync_regs = dev->sync_aperture;
35 /* disable the ip_busy_timeout. this prevents write drops, etc.
36 * there's no real way to recover from a hung client anyway.
37 */
38 writel(0, sync_regs + HOST1X_SYNC_IP_BUSY_TIMEOUT);
39
40 /* increase the auto-ack timout to the maximum value. 2d will hang
41 * otherwise on ap20.
42 */
43 writel(0xff, sync_regs + HOST1X_SYNC_CTXSW_TIMEOUT_CFG);
44}
45
46static void t20_intr_set_host_clocks_per_usec(struct nvhost_intr *intr, u32 cpm)
47{
48 struct nvhost_master *dev = intr_to_dev(intr);
49 void __iomem *sync_regs = dev->sync_aperture;
50 /* write microsecond clock register */
51 writel(cpm, sync_regs + HOST1X_SYNC_USEC_CLK);
52}
53
54static void t20_intr_set_syncpt_threshold(struct nvhost_intr *intr,
55 u32 id, u32 thresh)
56{
57 struct nvhost_master *dev = intr_to_dev(intr);
58 void __iomem *sync_regs = dev->sync_aperture;
59 thresh &= 0xffff;
60 writel(thresh, sync_regs + (HOST1X_SYNC_SYNCPT_INT_THRESH_0 + id * 4));
61}
62
63static void t20_intr_enable_syncpt_intr(struct nvhost_intr *intr, u32 id)
64{
65 struct nvhost_master *dev = intr_to_dev(intr);
66 void __iomem *sync_regs = dev->sync_aperture;
67 writel(BIT(id), sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0);
68}
69
70static void t20_intr_disable_all_syncpt_intrs(struct nvhost_intr *intr)
71{
72 struct nvhost_master *dev = intr_to_dev(intr);
73 void __iomem *sync_regs = dev->sync_aperture;
74 /* disable interrupts for both cpu's */
75 writel(0, sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
76
77 /* clear status for both cpu's */
78 writel(0xffffffffu, sync_regs +
79 HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
80 writel(0xffffffffu, sync_regs +
81 HOST1X_SYNC_SYNCPT_THRESH_CPU1_INT_STATUS);
82}
83
84/**
85 * Sync point threshold interrupt service function
86 * Handles sync point threshold triggers, in interrupt context
87 */
88irqreturn_t t20_intr_syncpt_thresh_isr(int irq, void *dev_id)
89{
90 struct nvhost_intr_syncpt *syncpt = dev_id;
91 unsigned int id = syncpt->id;
92 struct nvhost_intr *intr = intr_syncpt_to_intr(syncpt);
93
94 void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
95
96 writel(BIT(id),
97 sync_regs + HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE);
98 writel(BIT(id),
99 sync_regs + HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS);
100
101 return IRQ_WAKE_THREAD;
102}
103
104/**
105 * Host general interrupt service function
106 * Handles read / write failures
107 */
108static irqreturn_t t20_intr_host1x_isr(int irq, void *dev_id)
109{
110 struct nvhost_intr *intr = dev_id;
111 void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
112 u32 stat;
113 u32 ext_stat;
114 u32 addr;
115
116 stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS);
117 ext_stat = readl(sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
118
119 if (HOST1X_VAL(SYNC_HINTSTATUS_EXT, IP_READ_INT, ext_stat)) {
120 addr = readl(sync_regs + HOST1X_SYNC_IP_READ_TIMEOUT_ADDR);
121 pr_err("Host read timeout at address %x\n", addr);
122 }
123
124 if (HOST1X_VAL(SYNC_HINTSTATUS_EXT, IP_WRITE_INT, ext_stat)) {
125 addr = readl(sync_regs + HOST1X_SYNC_IP_WRITE_TIMEOUT_ADDR);
126 pr_err("Host write timeout at address %x\n", addr);
127 }
128
129 writel(ext_stat, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
130 writel(stat, sync_regs + HOST1X_SYNC_HINTSTATUS);
131
132 return IRQ_HANDLED;
133}
134static int t20_intr_request_host_general_irq(struct nvhost_intr *intr)
135{
136 void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
137 int err;
138
139 if (intr->host_general_irq_requested)
140 return 0;
141
142 /* master disable for general (not syncpt) host interrupts */
143 writel(0, sync_regs + HOST1X_SYNC_INTMASK);
144
145 /* clear status & extstatus */
146 writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS_EXT);
147 writel(0xfffffffful, sync_regs + HOST1X_SYNC_HINTSTATUS);
148
149 err = request_irq(intr->host_general_irq, t20_intr_host1x_isr, 0,
150 "host_status", intr);
151 if (err)
152 return err;
153
154 /* enable extra interrupt sources IP_READ_INT and IP_WRITE_INT */
155 writel(BIT(30) | BIT(31), sync_regs + HOST1X_SYNC_HINTMASK_EXT);
156
157 /* enable extra interrupt sources */
158 writel(BIT(31), sync_regs + HOST1X_SYNC_HINTMASK);
159
160 /* enable host module interrupt to CPU0 */
161 writel(BIT(0), sync_regs + HOST1X_SYNC_INTC0MASK);
162
163 /* master enable for general (not syncpt) host interrupts */
164 writel(BIT(0), sync_regs + HOST1X_SYNC_INTMASK);
165
166 intr->host_general_irq_requested = true;
167
168 return err;
169}
170
171static void t20_intr_free_host_general_irq(struct nvhost_intr *intr)
172{
173 if (intr->host_general_irq_requested) {
174 void __iomem *sync_regs = intr_to_dev(intr)->sync_aperture;
175
176 /* master disable for general (not syncpt) host interrupts */
177 writel(0, sync_regs + HOST1X_SYNC_INTMASK);
178
179 free_irq(intr->host_general_irq, intr);
180 intr->host_general_irq_requested = false;
181 }
182}
183
184static int t20_request_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
185{
186 int err;
187 if (syncpt->irq_requested)
188 return 0;
189
190 err = request_threaded_irq(syncpt->irq,
191 t20_intr_syncpt_thresh_isr,
192 nvhost_syncpt_thresh_fn,
193 0, syncpt->thresh_irq_name, syncpt);
194 if (err)
195 return err;
196
197 syncpt->irq_requested = 1;
198 return 0;
199}
200
201int nvhost_init_t20_intr_support(struct nvhost_master *host)
202{
203 host->op.intr.init_host_sync = t20_intr_init_host_sync;
204 host->op.intr.set_host_clocks_per_usec =
205 t20_intr_set_host_clocks_per_usec;
206 host->op.intr.set_syncpt_threshold = t20_intr_set_syncpt_threshold;
207 host->op.intr.enable_syncpt_intr = t20_intr_enable_syncpt_intr;
208 host->op.intr.disable_all_syncpt_intrs =
209 t20_intr_disable_all_syncpt_intrs;
210 host->op.intr.request_host_general_irq =
211 t20_intr_request_host_general_irq;
212 host->op.intr.free_host_general_irq =
213 t20_intr_free_host_general_irq;
214 host->op.intr.request_syncpt_irq =
215 t20_request_syncpt_irq;
216
217 return 0;
218}
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.c b/drivers/video/tegra/host/host1x/host1x_syncpt.c
new file mode 100644
index 00000000000..b0fd9970aaa
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.c
@@ -0,0 +1,248 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_syncpt.c
3 *
4 * Tegra Graphics Host Syncpoints for HOST1X
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/nvhost_ioctl.h>
22#include "nvhost_syncpt.h"
23#include "dev.h"
24#include "host1x_syncpt.h"
25#include "host1x_hardware.h"
26
27/**
28 * Write the current syncpoint value back to hw.
29 */
30static void t20_syncpt_reset(struct nvhost_syncpt *sp, u32 id)
31{
32 struct nvhost_master *dev = syncpt_to_dev(sp);
33 int min = nvhost_syncpt_read_min(sp, id);
34 writel(min, dev->sync_aperture + (HOST1X_SYNC_SYNCPT_0 + id * 4));
35}
36
37/**
38 * Write the current waitbase value back to hw.
39 */
40static void t20_syncpt_reset_wait_base(struct nvhost_syncpt *sp, u32 id)
41{
42 struct nvhost_master *dev = syncpt_to_dev(sp);
43 writel(sp->base_val[id],
44 dev->sync_aperture + (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
45}
46
47/**
48 * Read waitbase value from hw.
49 */
50static void t20_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
51{
52 struct nvhost_master *dev = syncpt_to_dev(sp);
53 sp->base_val[id] = readl(dev->sync_aperture +
54 (HOST1X_SYNC_SYNCPT_BASE_0 + id * 4));
55}
56
57/**
58 * Updates the last value read from hardware.
59 * (was nvhost_syncpt_update_min)
60 */
61static u32 t20_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
62{
63 struct nvhost_master *dev = syncpt_to_dev(sp);
64 void __iomem *sync_regs = dev->sync_aperture;
65 u32 old, live;
66
67 do {
68 old = nvhost_syncpt_read_min(sp, id);
69 live = readl(sync_regs + (HOST1X_SYNC_SYNCPT_0 + id * 4));
70 } while ((u32)atomic_cmpxchg(&sp->min_val[id], old, live) != old);
71
72 if (!nvhost_syncpt_check_max(sp, id, live))
73 dev_err(&syncpt_to_dev(sp)->dev->dev,
74 "%s failed: id=%u\n",
75 __func__,
76 id);
77
78 return live;
79}
80
81/**
82 * Write a cpu syncpoint increment to the hardware, without touching
83 * the cache. Caller is responsible for host being powered.
84 */
85static void t20_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
86{
87 struct nvhost_master *dev = syncpt_to_dev(sp);
88 BUG_ON(!nvhost_module_powered(dev->dev));
89 if (!client_managed(id) && nvhost_syncpt_min_eq_max(sp, id)) {
90 dev_err(&syncpt_to_dev(sp)->dev->dev,
91 "Trying to increment syncpoint id %d beyond max\n",
92 id);
93 nvhost_debug_dump(syncpt_to_dev(sp));
94 return;
95 }
96 writel(BIT(id), dev->sync_aperture + HOST1X_SYNC_SYNCPT_CPU_INCR);
97 wmb();
98}
99
100/* check for old WAITs to be removed (avoiding a wrap) */
101static int t20_syncpt_wait_check(struct nvhost_syncpt *sp,
102 struct nvmap_client *nvmap,
103 u32 waitchk_mask,
104 struct nvhost_waitchk *wait,
105 int num_waitchk)
106{
107 u32 idx;
108 int err = 0;
109
110 /* get current syncpt values */
111 for (idx = 0; idx < NV_HOST1X_SYNCPT_NB_PTS; idx++) {
112 if (BIT(idx) & waitchk_mask)
113 nvhost_syncpt_update_min(sp, idx);
114 }
115
116 BUG_ON(!wait && !num_waitchk);
117
118 /* compare syncpt vs wait threshold */
119 while (num_waitchk) {
120 u32 override;
121
122 BUG_ON(wait->syncpt_id >= NV_HOST1X_SYNCPT_NB_PTS);
123 if (nvhost_syncpt_is_expired(sp,
124 wait->syncpt_id, wait->thresh)) {
125 /*
126 * NULL an already satisfied WAIT_SYNCPT host method,
127 * by patching its args in the command stream. The
128 * method data is changed to reference a reserved
129 * (never given out or incr) NVSYNCPT_GRAPHICS_HOST
130 * syncpt with a matching threshold value of 0, so
131 * is guaranteed to be popped by the host HW.
132 */
133 dev_dbg(&syncpt_to_dev(sp)->dev->dev,
134 "drop WAIT id %d (%s) thresh 0x%x, min 0x%x\n",
135 wait->syncpt_id,
136 syncpt_op(sp).name(sp, wait->syncpt_id),
137 wait->thresh,
138 nvhost_syncpt_read_min(sp, wait->syncpt_id));
139
140 /* patch the wait */
141 override = nvhost_class_host_wait_syncpt(
142 NVSYNCPT_GRAPHICS_HOST, 0);
143 err = nvmap_patch_word(nvmap,
144 (struct nvmap_handle *)wait->mem,
145 wait->offset, override);
146 if (err)
147 break;
148 }
149
150 wait++;
151 num_waitchk--;
152 }
153 return err;
154}
155
156
157static const char *s_syncpt_names[32] = {
158 "gfx_host",
159 "", "", "", "", "", "", "",
160 "disp0_a", "disp1_a", "avp_0",
161 "csi_vi_0", "csi_vi_1",
162 "vi_isp_0", "vi_isp_1", "vi_isp_2", "vi_isp_3", "vi_isp_4",
163 "2d_0", "2d_1",
164 "disp0_b", "disp1_b",
165 "3d",
166 "mpe",
167 "disp0_c", "disp1_c",
168 "vblank0", "vblank1",
169 "mpe_ebm_eof", "mpe_wr_safe",
170 "2d_tinyblt",
171 "dsi"
172};
173
174static const char *t20_syncpt_name(struct nvhost_syncpt *s, u32 id)
175{
176 BUG_ON(id >= ARRAY_SIZE(s_syncpt_names));
177 return s_syncpt_names[id];
178}
179
180static void t20_syncpt_debug(struct nvhost_syncpt *sp)
181{
182 u32 i;
183 for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
184 u32 max = nvhost_syncpt_read_max(sp, i);
185 u32 min = nvhost_syncpt_update_min(sp, i);
186 if (!max && !min)
187 continue;
188 dev_info(&syncpt_to_dev(sp)->dev->dev,
189 "id %d (%s) min %d max %d\n",
190 i, syncpt_op(sp).name(sp, i),
191 min, max);
192
193 }
194
195 for (i = 0; i < NV_HOST1X_SYNCPT_NB_BASES; i++) {
196 u32 base_val;
197 t20_syncpt_read_wait_base(sp, i);
198 base_val = sp->base_val[i];
199 if (base_val)
200 dev_info(&syncpt_to_dev(sp)->dev->dev,
201 "waitbase id %d val %d\n",
202 i, base_val);
203
204 }
205}
206
207static int syncpt_mutex_try_lock(struct nvhost_syncpt *sp,
208 unsigned int idx)
209{
210 void __iomem *sync_regs = syncpt_to_dev(sp)->sync_aperture;
211 /* mlock registers returns 0 when the lock is aquired.
212 * writing 0 clears the lock. */
213 return !!readl(sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
214}
215
216static void syncpt_mutex_unlock(struct nvhost_syncpt *sp,
217 unsigned int idx)
218{
219 void __iomem *sync_regs = syncpt_to_dev(sp)->sync_aperture;
220
221 writel(0, sync_regs + (HOST1X_SYNC_MLOCK_0 + idx * 4));
222}
223
224int host1x_init_syncpt_support(struct nvhost_master *host)
225{
226
227 host->sync_aperture = host->aperture +
228 (NV_HOST1X_CHANNEL0_BASE +
229 HOST1X_CHANNEL_SYNC_REG_BASE);
230
231 host->op.syncpt.reset = t20_syncpt_reset;
232 host->op.syncpt.reset_wait_base = t20_syncpt_reset_wait_base;
233 host->op.syncpt.read_wait_base = t20_syncpt_read_wait_base;
234 host->op.syncpt.update_min = t20_syncpt_update_min;
235 host->op.syncpt.cpu_incr = t20_syncpt_cpu_incr;
236 host->op.syncpt.wait_check = t20_syncpt_wait_check;
237 host->op.syncpt.debug = t20_syncpt_debug;
238 host->op.syncpt.name = t20_syncpt_name;
239 host->op.syncpt.mutex_try_lock = syncpt_mutex_try_lock;
240 host->op.syncpt.mutex_unlock = syncpt_mutex_unlock;
241
242 host->syncpt.nb_pts = NV_HOST1X_SYNCPT_NB_PTS;
243 host->syncpt.nb_bases = NV_HOST1X_SYNCPT_NB_BASES;
244 host->syncpt.client_managed = NVSYNCPTS_CLIENT_MANAGED;
245 host->syncpt.nb_mlocks = NV_HOST1X_SYNC_MLOCK_NUM;
246
247 return 0;
248}
diff --git a/drivers/video/tegra/host/host1x/host1x_syncpt.h b/drivers/video/tegra/host/host1x/host1x_syncpt.h
new file mode 100644
index 00000000000..0d263dc92ed
--- /dev/null
+++ b/drivers/video/tegra/host/host1x/host1x_syncpt.h
@@ -0,0 +1,77 @@
1/*
2 * drivers/video/tegra/host/host1x/host1x_syncpt.h
3 *
4 * Tegra Graphics Host Syncpoints for HOST1X
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_HOST1X_HOST1X_SYNCPT_H
22#define __NVHOST_HOST1X_HOST1X_SYNCPT_H
23
24#define NVSYNCPT_DISP0_A (8)
25#define NVSYNCPT_DISP1_A (9)
26#define NVSYNCPT_AVP_0 (10)
27#define NVSYNCPT_CSI_VI_0 (11)
28#define NVSYNCPT_CSI_VI_1 (12)
29#define NVSYNCPT_VI_ISP_0 (13)
30#define NVSYNCPT_VI_ISP_1 (14)
31#define NVSYNCPT_VI_ISP_2 (15)
32#define NVSYNCPT_VI_ISP_3 (16)
33#define NVSYNCPT_VI_ISP_4 (17)
34#define NVSYNCPT_2D_0 (18)
35#define NVSYNCPT_2D_1 (19)
36#define NVSYNCPT_DISP0_B (20)
37#define NVSYNCPT_DISP1_B (21)
38#define NVSYNCPT_3D (22)
39#define NVSYNCPT_MPE (23)
40#define NVSYNCPT_DISP0_C (24)
41#define NVSYNCPT_DISP1_C (25)
42#define NVSYNCPT_VBLANK0 (26)
43#define NVSYNCPT_VBLANK1 (27)
44#define NVSYNCPT_MPE_EBM_EOF (28)
45#define NVSYNCPT_MPE_WR_SAFE (29)
46#define NVSYNCPT_DSI (31)
47
48
49/*#define NVSYNCPT_2D_CHANNEL2_0 (20) */
50/*#define NVSYNCPT_2D_CHANNEL2_1 (21) */
51/*#define NVSYNCPT_2D_TINYBLT_WAR (30)*/
52/*#define NVSYNCPT_2D_TINYBLT_RESTORE_CLASS_ID (30)*/
53
54/* sync points that are wholly managed by the client */
55#define NVSYNCPTS_CLIENT_MANAGED ( \
56 BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) | \
57 BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) | \
58 BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) | \
59 BIT(NVSYNCPT_DSI) | \
60 BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1) | \
61 BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) | \
62 BIT(NVSYNCPT_VI_ISP_1) | BIT(NVSYNCPT_VI_ISP_2) | \
63 BIT(NVSYNCPT_VI_ISP_3) | BIT(NVSYNCPT_VI_ISP_4) | \
64 BIT(NVSYNCPT_MPE_EBM_EOF) | BIT(NVSYNCPT_MPE_WR_SAFE) | \
65 BIT(NVSYNCPT_2D_1) | BIT(NVSYNCPT_AVP_0))
66
67
68#define NVWAITBASE_2D_0 (1)
69#define NVWAITBASE_2D_1 (2)
70#define NVWAITBASE_3D (3)
71#define NVWAITBASE_MPE (4)
72
73struct nvhost_master;
74int host1x_init_syncpt(struct nvhost_master *host);
75int host1x_init_syncpt_support(struct nvhost_master *host);
76
77#endif
diff --git a/drivers/video/tegra/host/isp/Makefile b/drivers/video/tegra/host/isp/Makefile
new file mode 100644
index 00000000000..7bcdc33c83d
--- /dev/null
+++ b/drivers/video/tegra/host/isp/Makefile
@@ -0,0 +1,7 @@
1GCOV_PROFILE := y
2EXTRA_CFLAGS += -Idrivers/video/tegra/host
3
4nvhost-isp-objs = \
5 isp.o
6
7obj-$(CONFIG_TEGRA_GRHOST) += nvhost-isp.o
diff --git a/drivers/video/tegra/host/isp/isp.c b/drivers/video/tegra/host/isp/isp.c
new file mode 100644
index 00000000000..f39dc644b27
--- /dev/null
+++ b/drivers/video/tegra/host/isp/isp.c
@@ -0,0 +1,82 @@
1/*
2 * drivers/video/tegra/host/isp/isp.c
3 *
4 * Tegra Graphics ISP
5 *
6 * Copyright (c) 2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "dev.h"
22#include "bus_client.h"
23
24static int __devinit isp_probe(struct nvhost_device *dev)
25{
26 return nvhost_client_device_init(dev);
27}
28
29static int __exit isp_remove(struct nvhost_device *dev)
30{
31 /* Add clean-up */
32 return 0;
33}
34
35static int isp_suspend(struct nvhost_device *dev, pm_message_t state)
36{
37 return nvhost_client_device_suspend(dev);
38}
39
40static int isp_resume(struct nvhost_device *dev)
41{
42 dev_info(&dev->dev, "resuming\n");
43 return 0;
44}
45
46struct nvhost_device *isp_device;
47
48static struct nvhost_driver isp_driver = {
49 .probe = isp_probe,
50 .remove = __exit_p(isp_remove),
51#ifdef CONFIG_PM
52 .suspend = isp_suspend,
53 .resume = isp_resume,
54#endif
55 .driver = {
56 .owner = THIS_MODULE,
57 .name = "isp",
58 }
59};
60
61static int __init isp_init(void)
62{
63 int err;
64
65 isp_device = nvhost_get_device("isp");
66 if (!isp_device)
67 return -ENXIO;
68
69 err = nvhost_device_register(isp_device);
70 if (err)
71 return err;
72
73 return nvhost_driver_register(&isp_driver);
74}
75
76static void __exit isp_exit(void)
77{
78 nvhost_driver_unregister(&isp_driver);
79}
80
81module_init(isp_init);
82module_exit(isp_exit);
diff --git a/drivers/video/tegra/host/mpe/Makefile b/drivers/video/tegra/host/mpe/Makefile
new file mode 100644
index 00000000000..efd77bb88fe
--- /dev/null
+++ b/drivers/video/tegra/host/mpe/Makefile
@@ -0,0 +1,7 @@
1GCOV_PROFILE := y
2EXTRA_CFLAGS += -Idrivers/video/tegra/host
3
4nvhost-mpe-objs = \
5 mpe.o
6
7obj-$(CONFIG_TEGRA_GRHOST) += nvhost-mpe.o
diff --git a/drivers/video/tegra/host/mpe/mpe.c b/drivers/video/tegra/host/mpe/mpe.c
new file mode 100644
index 00000000000..28002aa637a
--- /dev/null
+++ b/drivers/video/tegra/host/mpe/mpe.c
@@ -0,0 +1,638 @@
1/*
2 * drivers/video/tegra/host/mpe/mpe.c
3 *
4 * Tegra Graphics Host MPE
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_hwctx.h"
22#include "dev.h"
23#include "host1x/host1x_hardware.h"
24#include "host1x/host1x_channel.h"
25#include "host1x/host1x_syncpt.h"
26#include "host1x/host1x_hwctx.h"
27#include "t20/t20.h"
28#include <linux/slab.h>
29#include "bus_client.h"
30
31enum {
32 HWCTX_REGINFO_NORMAL = 0,
33 HWCTX_REGINFO_STASH,
34 HWCTX_REGINFO_CALCULATE,
35 HWCTX_REGINFO_WRITEBACK
36};
37
38const struct hwctx_reginfo ctxsave_regs_mpe[] = {
39 HWCTX_REGINFO(0x124, 1, STASH),
40 HWCTX_REGINFO(0x123, 1, STASH),
41 HWCTX_REGINFO(0x103, 1, STASH),
42 HWCTX_REGINFO(0x074, 1, STASH),
43 HWCTX_REGINFO(0x021, 1, NORMAL),
44 HWCTX_REGINFO(0x020, 1, STASH),
45 HWCTX_REGINFO(0x024, 2, NORMAL),
46 HWCTX_REGINFO(0x0e6, 1, NORMAL),
47 HWCTX_REGINFO(0x3fc, 1, NORMAL),
48 HWCTX_REGINFO(0x3d0, 1, NORMAL),
49 HWCTX_REGINFO(0x3d4, 1, NORMAL),
50 HWCTX_REGINFO(0x013, 1, NORMAL),
51 HWCTX_REGINFO(0x022, 1, NORMAL),
52 HWCTX_REGINFO(0x030, 4, NORMAL),
53 HWCTX_REGINFO(0x023, 1, NORMAL),
54 HWCTX_REGINFO(0x070, 1, NORMAL),
55 HWCTX_REGINFO(0x0a0, 9, NORMAL),
56 HWCTX_REGINFO(0x071, 1, NORMAL),
57 HWCTX_REGINFO(0x100, 4, NORMAL),
58 HWCTX_REGINFO(0x104, 2, NORMAL),
59 HWCTX_REGINFO(0x108, 9, NORMAL),
60 HWCTX_REGINFO(0x112, 2, NORMAL),
61 HWCTX_REGINFO(0x114, 1, STASH),
62 HWCTX_REGINFO(0x014, 1, NORMAL),
63 HWCTX_REGINFO(0x072, 1, NORMAL),
64 HWCTX_REGINFO(0x200, 1, NORMAL),
65 HWCTX_REGINFO(0x0d1, 1, NORMAL),
66 HWCTX_REGINFO(0x0d0, 1, NORMAL),
67 HWCTX_REGINFO(0x0c0, 1, NORMAL),
68 HWCTX_REGINFO(0x0c3, 2, NORMAL),
69 HWCTX_REGINFO(0x0d2, 1, NORMAL),
70 HWCTX_REGINFO(0x0d8, 1, NORMAL),
71 HWCTX_REGINFO(0x0e0, 2, NORMAL),
72 HWCTX_REGINFO(0x07f, 2, NORMAL),
73 HWCTX_REGINFO(0x084, 8, NORMAL),
74 HWCTX_REGINFO(0x0d3, 1, NORMAL),
75 HWCTX_REGINFO(0x040, 13, NORMAL),
76 HWCTX_REGINFO(0x050, 6, NORMAL),
77 HWCTX_REGINFO(0x058, 1, NORMAL),
78 HWCTX_REGINFO(0x057, 1, NORMAL),
79 HWCTX_REGINFO(0x111, 1, NORMAL),
80 HWCTX_REGINFO(0x130, 3, NORMAL),
81 HWCTX_REGINFO(0x201, 1, NORMAL),
82 HWCTX_REGINFO(0x068, 2, NORMAL),
83 HWCTX_REGINFO(0x08c, 1, NORMAL),
84 HWCTX_REGINFO(0x0cf, 1, NORMAL),
85 HWCTX_REGINFO(0x082, 2, NORMAL),
86 HWCTX_REGINFO(0x075, 1, NORMAL),
87 HWCTX_REGINFO(0x0e8, 1, NORMAL),
88 HWCTX_REGINFO(0x056, 1, NORMAL),
89 HWCTX_REGINFO(0x057, 1, NORMAL),
90 HWCTX_REGINFO(0x073, 1, CALCULATE),
91 HWCTX_REGINFO(0x074, 1, NORMAL),
92 HWCTX_REGINFO(0x075, 1, NORMAL),
93 HWCTX_REGINFO(0x076, 1, STASH),
94 HWCTX_REGINFO(0x11a, 9, NORMAL),
95 HWCTX_REGINFO(0x123, 1, NORMAL),
96 HWCTX_REGINFO(0x124, 1, NORMAL),
97 HWCTX_REGINFO(0x12a, 5, NORMAL),
98 HWCTX_REGINFO(0x12f, 1, STASH),
99 HWCTX_REGINFO(0x125, 2, NORMAL),
100 HWCTX_REGINFO(0x034, 1, NORMAL),
101 HWCTX_REGINFO(0x133, 2, NORMAL),
102 HWCTX_REGINFO(0x127, 1, NORMAL),
103 HWCTX_REGINFO(0x106, 1, WRITEBACK),
104 HWCTX_REGINFO(0x107, 1, WRITEBACK)
105};
106
107#define NR_STASHES 8
108#define NR_WRITEBACKS 2
109
110#define RC_RAM_LOAD_CMD 0x115
111#define RC_RAM_LOAD_DATA 0x116
112#define RC_RAM_READ_CMD 0x128
113#define RC_RAM_READ_DATA 0x129
114#define RC_RAM_SIZE 692
115
116#define IRFR_RAM_LOAD_CMD 0xc5
117#define IRFR_RAM_LOAD_DATA 0xc6
118#define IRFR_RAM_READ_CMD 0xcd
119#define IRFR_RAM_READ_DATA 0xce
120#define IRFR_RAM_SIZE 408
121
122struct mpe_save_info {
123 u32 in[NR_STASHES];
124 u32 out[NR_WRITEBACKS];
125 unsigned in_pos;
126 unsigned out_pos;
127 u32 h264_mode;
128};
129
130
131/*** restore ***/
132
133static unsigned int restore_size;
134
135static void restore_begin(struct host1x_hwctx_handler *h, u32 *ptr)
136{
137 /* set class to host */
138 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
139 NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
140 /* increment sync point base */
141 ptr[1] = nvhost_class_host_incr_syncpt_base(h->waitbase, 1);
142 /* set class to MPE */
143 ptr[2] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
144}
145#define RESTORE_BEGIN_SIZE 3
146
147static void restore_ram(u32 *ptr, unsigned words,
148 unsigned cmd_reg, unsigned data_reg)
149{
150 ptr[0] = nvhost_opcode_imm(cmd_reg, words);
151 ptr[1] = nvhost_opcode_nonincr(data_reg, words);
152}
153#define RESTORE_RAM_SIZE 2
154
155static void restore_end(struct host1x_hwctx_handler *h, u32 *ptr)
156{
157 /* syncpt increment to track restore gather. */
158 ptr[0] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE,
159 h->syncpt);
160}
161#define RESTORE_END_SIZE 1
162
163static u32 *setup_restore_regs(u32 *ptr,
164 const struct hwctx_reginfo *regs,
165 unsigned int nr_regs)
166{
167 const struct hwctx_reginfo *rend = regs + nr_regs;
168
169 for ( ; regs != rend; ++regs) {
170 u32 offset = regs->offset;
171 u32 count = regs->count;
172 *ptr++ = nvhost_opcode_incr(offset, count);
173 ptr += count;
174 }
175 return ptr;
176}
177
178static u32 *setup_restore_ram(u32 *ptr, unsigned words,
179 unsigned cmd_reg, unsigned data_reg)
180{
181 restore_ram(ptr, words, cmd_reg, data_reg);
182 return ptr + (RESTORE_RAM_SIZE + words);
183}
184
185static void setup_restore(struct host1x_hwctx_handler *h, u32 *ptr)
186{
187 restore_begin(h, ptr);
188 ptr += RESTORE_BEGIN_SIZE;
189
190 ptr = setup_restore_regs(ptr, ctxsave_regs_mpe,
191 ARRAY_SIZE(ctxsave_regs_mpe));
192
193 ptr = setup_restore_ram(ptr, RC_RAM_SIZE,
194 RC_RAM_LOAD_CMD, RC_RAM_LOAD_DATA);
195
196 ptr = setup_restore_ram(ptr, IRFR_RAM_SIZE,
197 IRFR_RAM_LOAD_CMD, IRFR_RAM_LOAD_DATA);
198
199 restore_end(h, ptr);
200
201 wmb();
202}
203
204
205/*** save ***/
206struct save_info {
207 u32 *ptr;
208 unsigned int save_count;
209 unsigned int restore_count;
210};
211
212static void __init save_begin(struct host1x_hwctx_handler *h, u32 *ptr)
213{
214 /* MPE: when done, increment syncpt to base+1 */
215 ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
216 ptr[1] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_OP_DONE, h->syncpt);
217 /* host: wait for syncpt base+1 */
218 ptr[2] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
219 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
220 ptr[3] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 1);
221 /* host: signal context read thread to start reading */
222 ptr[4] = nvhost_opcode_imm_incr_syncpt(NV_SYNCPT_IMMEDIATE, h->syncpt);
223}
224#define SAVE_BEGIN_SIZE 5
225
226static void __init save_direct(u32 *ptr, u32 start_reg, u32 count)
227{
228 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
229 NV_CLASS_HOST_INDOFF, 1);
230 ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_MPE,
231 start_reg, true);
232 ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INDDATA, count);
233}
234#define SAVE_DIRECT_SIZE 3
235
236static void __init save_set_ram_cmd(u32 *ptr, u32 cmd_reg, u32 count)
237{
238 ptr[0] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID,
239 cmd_reg, 1);
240 ptr[1] = count;
241}
242#define SAVE_SET_RAM_CMD_SIZE 2
243
244static void __init save_read_ram_data_nasty(u32 *ptr, u32 data_reg)
245{
246 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
247 NV_CLASS_HOST_INDOFF, 1);
248 ptr[1] = nvhost_class_host_indoff_reg_read(NV_HOST_MODULE_MPE,
249 data_reg, false);
250 ptr[2] = nvhost_opcode_imm(NV_CLASS_HOST_INDDATA, 0);
251 /* write junk data to avoid 'cached problem with register memory' */
252 ptr[3] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID,
253 data_reg, 1);
254 ptr[4] = 0x99;
255}
256#define SAVE_READ_RAM_DATA_NASTY_SIZE 5
257
258static void __init save_end(struct host1x_hwctx_handler *h, u32 *ptr)
259{
260 /* Wait for context read service to finish (cpu incr 3) */
261 ptr[0] = nvhost_opcode_setclass(NV_HOST1X_CLASS_ID,
262 NV_CLASS_HOST_WAIT_SYNCPT_BASE, 1);
263 ptr[1] = nvhost_class_host_wait_syncpt_base(h->syncpt, h->waitbase, 3);
264 /* Advance syncpoint base */
265 ptr[2] = nvhost_opcode_nonincr(NV_CLASS_HOST_INCR_SYNCPT_BASE, 1);
266 ptr[3] = nvhost_class_host_incr_syncpt_base(h->waitbase, 3);
267 /* set class back to the unit */
268 ptr[4] = nvhost_opcode_setclass(NV_VIDEO_ENCODE_MPEG_CLASS_ID, 0, 0);
269}
270#define SAVE_END_SIZE 5
271
272static void __init setup_save_regs(struct save_info *info,
273 const struct hwctx_reginfo *regs,
274 unsigned int nr_regs)
275{
276 const struct hwctx_reginfo *rend = regs + nr_regs;
277 u32 *ptr = info->ptr;
278 unsigned int save_count = info->save_count;
279 unsigned int restore_count = info->restore_count;
280
281 for ( ; regs != rend; ++regs) {
282 u32 offset = regs->offset;
283 u32 count = regs->count;
284 if (regs->type != HWCTX_REGINFO_WRITEBACK) {
285 if (ptr) {
286 save_direct(ptr, offset, count);
287 ptr += SAVE_DIRECT_SIZE;
288 memset(ptr, 0, count * 4);
289 ptr += count;
290 }
291 save_count += (SAVE_DIRECT_SIZE + count);
292 }
293 restore_count += (1 + count);
294 }
295
296 info->ptr = ptr;
297 info->save_count = save_count;
298 info->restore_count = restore_count;
299}
300
301static void __init setup_save_ram_nasty(struct save_info *info, unsigned words,
302 unsigned cmd_reg, unsigned data_reg)
303{
304 u32 *ptr = info->ptr;
305 unsigned int save_count = info->save_count;
306 unsigned int restore_count = info->restore_count;
307 unsigned i;
308
309 if (ptr) {
310 save_set_ram_cmd(ptr, cmd_reg, words);
311 ptr += SAVE_SET_RAM_CMD_SIZE;
312 for (i = words; i; --i) {
313 save_read_ram_data_nasty(ptr, data_reg);
314 ptr += SAVE_READ_RAM_DATA_NASTY_SIZE;
315 }
316 }
317
318 save_count += SAVE_SET_RAM_CMD_SIZE;
319 save_count += words * SAVE_READ_RAM_DATA_NASTY_SIZE;
320 restore_count += (RESTORE_RAM_SIZE + words);
321
322 info->ptr = ptr;
323 info->save_count = save_count;
324 info->restore_count = restore_count;
325}
326
327static void __init setup_save(struct host1x_hwctx_handler *h, u32 *ptr)
328{
329 struct save_info info = {
330 ptr,
331 SAVE_BEGIN_SIZE,
332 RESTORE_BEGIN_SIZE
333 };
334
335 if (info.ptr) {
336 save_begin(h, info.ptr);
337 info.ptr += SAVE_BEGIN_SIZE;
338 }
339
340 setup_save_regs(&info, ctxsave_regs_mpe,
341 ARRAY_SIZE(ctxsave_regs_mpe));
342
343 setup_save_ram_nasty(&info, RC_RAM_SIZE,
344 RC_RAM_READ_CMD, RC_RAM_READ_DATA);
345
346 setup_save_ram_nasty(&info, IRFR_RAM_SIZE,
347 IRFR_RAM_READ_CMD, IRFR_RAM_READ_DATA);
348
349 if (info.ptr) {
350 save_end(h, info.ptr);
351 info.ptr += SAVE_END_SIZE;
352 }
353
354 wmb();
355
356 h->save_size = info.save_count + SAVE_END_SIZE;
357 restore_size = info.restore_count + RESTORE_END_SIZE;
358}
359
360
361static u32 calculate_mpe(u32 word, struct mpe_save_info *msi)
362{
363 u32 buffer_full_read = msi->in[0] & 0x01ffffff;
364 u32 byte_len = msi->in[1];
365 u32 drain = (msi->in[2] >> 2) & 0x007fffff;
366 u32 rep_frame = msi->in[3] & 0x0000ffff;
367 u32 h264_mode = (msi->in[4] >> 11) & 1;
368 int new_buffer_full;
369
370 if (h264_mode)
371 byte_len >>= 3;
372 new_buffer_full = buffer_full_read + byte_len - (drain * 4);
373 msi->out[0] = max(0, new_buffer_full);
374 msi->out[1] = rep_frame;
375 if (rep_frame == 0)
376 word &= 0xffff0000;
377 return word;
378}
379
380static u32 *save_regs(u32 *ptr, unsigned int *pending,
381 struct nvhost_channel *channel,
382 const struct hwctx_reginfo *regs,
383 unsigned int nr_regs,
384 struct mpe_save_info *msi)
385{
386 const struct hwctx_reginfo *rend = regs + nr_regs;
387
388 for ( ; regs != rend; ++regs) {
389 u32 count = regs->count;
390 ++ptr; /* restore incr */
391 if (regs->type == HWCTX_REGINFO_NORMAL) {
392 host1x_drain_read_fifo(channel->aperture,
393 ptr, count, pending);
394 ptr += count;
395 } else {
396 u32 word;
397 if (regs->type == HWCTX_REGINFO_WRITEBACK) {
398 BUG_ON(msi->out_pos >= NR_WRITEBACKS);
399 word = msi->out[msi->out_pos++];
400 } else {
401 host1x_drain_read_fifo(channel->aperture,
402 &word, 1, pending);
403 if (regs->type == HWCTX_REGINFO_STASH) {
404 BUG_ON(msi->in_pos >= NR_STASHES);
405 msi->in[msi->in_pos++] = word;
406 } else {
407 word = calculate_mpe(word, msi);
408 }
409 }
410 *ptr++ = word;
411 }
412 }
413 return ptr;
414}
415
416static u32 *save_ram(u32 *ptr, unsigned int *pending,
417 struct nvhost_channel *channel,
418 unsigned words, unsigned cmd_reg, unsigned data_reg)
419{
420 int err = 0;
421 ptr += RESTORE_RAM_SIZE;
422 err = host1x_drain_read_fifo(channel->aperture, ptr, words, pending);
423 WARN_ON(err);
424 return ptr + words;
425}
426
427
428/*** ctxmpe ***/
429
430static struct nvhost_hwctx *ctxmpe_alloc(struct nvhost_hwctx_handler *h,
431 struct nvhost_channel *ch)
432{
433 struct nvmap_client *nvmap = nvhost_get_host(ch->dev)->nvmap;
434 struct host1x_hwctx_handler *p = to_host1x_hwctx_handler(h);
435 struct host1x_hwctx *ctx;
436
437 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
438 if (!ctx)
439 return NULL;
440 ctx->restore = nvmap_alloc(nvmap, restore_size * 4, 32,
441 NVMAP_HANDLE_WRITE_COMBINE, 0);
442 if (IS_ERR_OR_NULL(ctx->restore)) {
443 kfree(ctx);
444 return NULL;
445 }
446
447 ctx->restore_virt = nvmap_mmap(ctx->restore);
448 if (!ctx->restore_virt) {
449 nvmap_free(nvmap, ctx->restore);
450 kfree(ctx);
451 return NULL;
452 }
453
454 kref_init(&ctx->hwctx.ref);
455 ctx->hwctx.h = &p->h;
456 ctx->hwctx.channel = ch;
457 ctx->hwctx.valid = false;
458 ctx->save_incrs = 3;
459 ctx->save_thresh = 2;
460 ctx->restore_phys = nvmap_pin(nvmap, ctx->restore);
461 ctx->restore_size = restore_size;
462 ctx->restore_incrs = 1;
463
464 setup_restore(p, ctx->restore_virt);
465
466 return &ctx->hwctx;
467}
468
469static void ctxmpe_get(struct nvhost_hwctx *ctx)
470{
471 kref_get(&ctx->ref);
472}
473
474static void ctxmpe_free(struct kref *ref)
475{
476 struct nvhost_hwctx *nctx = container_of(ref, struct nvhost_hwctx, ref);
477 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
478 struct nvmap_client *nvmap =
479 nvhost_get_host(nctx->channel->dev)->nvmap;
480
481 if (ctx->restore_virt)
482 nvmap_munmap(ctx->restore, ctx->restore_virt);
483 nvmap_unpin(nvmap, ctx->restore);
484 nvmap_free(nvmap, ctx->restore);
485 kfree(ctx);
486}
487
488static void ctxmpe_put(struct nvhost_hwctx *ctx)
489{
490 kref_put(&ctx->ref, ctxmpe_free);
491}
492
493static void ctxmpe_save_push(struct nvhost_hwctx *nctx,
494 struct nvhost_cdma *cdma)
495{
496 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
497 struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
498 nvhost_cdma_push(cdma,
499 nvhost_opcode_gather(h->save_size),
500 h->save_phys);
501}
502
503static void ctxmpe_save_service(struct nvhost_hwctx *nctx)
504{
505 struct host1x_hwctx *ctx = to_host1x_hwctx(nctx);
506 struct host1x_hwctx_handler *h = host1x_hwctx_handler(ctx);
507
508 u32 *ptr = (u32 *)ctx->restore_virt + RESTORE_BEGIN_SIZE;
509 unsigned int pending = 0;
510 struct mpe_save_info msi;
511
512 msi.in_pos = 0;
513 msi.out_pos = 0;
514
515 ptr = save_regs(ptr, &pending, nctx->channel,
516 ctxsave_regs_mpe, ARRAY_SIZE(ctxsave_regs_mpe), &msi);
517
518 ptr = save_ram(ptr, &pending, nctx->channel,
519 RC_RAM_SIZE, RC_RAM_READ_CMD, RC_RAM_READ_DATA);
520
521 ptr = save_ram(ptr, &pending, nctx->channel,
522 IRFR_RAM_SIZE, IRFR_RAM_READ_CMD, IRFR_RAM_READ_DATA);
523
524 wmb();
525 nvhost_syncpt_cpu_incr(&nvhost_get_host(nctx->channel->dev)->syncpt,
526 h->syncpt);
527}
528
529struct nvhost_hwctx_handler * __init nvhost_mpe_ctxhandler_init(
530 u32 syncpt, u32 waitbase,
531 struct nvhost_channel *ch)
532{
533 struct nvmap_client *nvmap;
534 u32 *save_ptr;
535 struct host1x_hwctx_handler *p;
536
537 p = kmalloc(sizeof(*p), GFP_KERNEL);
538 if (!p)
539 return NULL;
540
541 nvmap = nvhost_get_host(ch->dev)->nvmap;
542
543 p->syncpt = syncpt;
544 p->waitbase = waitbase;
545
546 setup_save(p, NULL);
547
548 p->save_buf = nvmap_alloc(nvmap, p->save_size * 4, 32,
549 NVMAP_HANDLE_WRITE_COMBINE, 0);
550 if (IS_ERR(p->save_buf)) {
551 p->save_buf = NULL;
552 return NULL;
553 }
554
555 save_ptr = nvmap_mmap(p->save_buf);
556 if (!save_ptr) {
557 nvmap_free(nvmap, p->save_buf);
558 p->save_buf = NULL;
559 return NULL;
560 }
561
562 p->save_phys = nvmap_pin(nvmap, p->save_buf);
563
564 setup_save(p, save_ptr);
565
566 p->h.alloc = ctxmpe_alloc;
567 p->h.save_push = ctxmpe_save_push;
568 p->h.save_service = ctxmpe_save_service;
569 p->h.get = ctxmpe_get;
570 p->h.put = ctxmpe_put;
571
572 return &p->h;
573}
574
575int nvhost_mpe_prepare_power_off(struct nvhost_device *dev)
576{
577 return host1x_save_context(dev, NVSYNCPT_MPE);
578}
579
580static int __devinit mpe_probe(struct nvhost_device *dev)
581{
582 return nvhost_client_device_init(dev);
583}
584
585static int __exit mpe_remove(struct nvhost_device *dev)
586{
587 /* Add clean-up */
588 return 0;
589}
590
591static int mpe_suspend(struct nvhost_device *dev, pm_message_t state)
592{
593 return nvhost_client_device_suspend(dev);
594}
595
596static int mpe_resume(struct nvhost_device *dev)
597{
598 dev_info(&dev->dev, "resuming\n");
599 return 0;
600}
601
602struct nvhost_device *mpe_device;
603
604static struct nvhost_driver mpe_driver = {
605 .probe = mpe_probe,
606 .remove = __exit_p(mpe_remove),
607#ifdef CONFIG_PM
608 .suspend = mpe_suspend,
609 .resume = mpe_resume,
610#endif
611 .driver = {
612 .owner = THIS_MODULE,
613 .name = "mpe",
614 }
615};
616
617static int __init mpe_init(void)
618{
619 int err;
620
621 mpe_device = nvhost_get_device("mpe");
622 if (!mpe_device)
623 return -ENXIO;
624
625 err = nvhost_device_register(mpe_device);
626 if (err)
627 return err;
628
629 return nvhost_driver_register(&mpe_driver);
630}
631
632static void __exit mpe_exit(void)
633{
634 nvhost_driver_unregister(&mpe_driver);
635}
636
637module_init(mpe_init);
638module_exit(mpe_exit);
diff --git a/drivers/video/tegra/host/mpe/mpe.h b/drivers/video/tegra/host/mpe/mpe.h
new file mode 100644
index 00000000000..1bc2a8a04c1
--- /dev/null
+++ b/drivers/video/tegra/host/mpe/mpe.h
@@ -0,0 +1,32 @@
1/*
2 * drivers/video/tegra/host/mpe/mpe.h
3 *
4 * Tegra Graphics Host MPE
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_MPE_MPE_H
22#define __NVHOST_MPE_MPE_H
23
24struct nvhost_hwctx_handler;
25struct nvhost_device;
26
27struct nvhost_hwctx_handler *nvhost_mpe_ctxhandler_init(
28 u32 syncpt, u32 waitbase,
29 struct nvhost_channel *ch);
30int nvhost_mpe_prepare_power_off(struct nvhost_device *dev);
31
32#endif
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
new file mode 100644
index 00000000000..318f209651a
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -0,0 +1,467 @@
1/*
2 * drivers/video/tegra/host/nvhost_acm.c
3 *
4 * Tegra Graphics Host Automatic Clock Management
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_acm.h"
22#include "dev.h"
23#include <linux/slab.h>
24#include <linux/string.h>
25#include <linux/sched.h>
26#include <linux/err.h>
27#include <linux/device.h>
28#include <linux/delay.h>
29#include <linux/platform_device.h>
30#include <mach/powergate.h>
31#include <mach/clk.h>
32#include <mach/hardware.h>
33
34#define ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT (2 * HZ)
35#define POWERGATE_DELAY 10
36#define MAX_DEVID_LENGTH 16
37
38DEFINE_MUTEX(client_list_lock);
39
40struct nvhost_module_client {
41 struct list_head node;
42 unsigned long rate[NVHOST_MODULE_MAX_CLOCKS];
43 void *priv;
44};
45
46static void do_powergate_locked(int id)
47{
48 if (id != -1 && tegra_powergate_is_powered(id))
49 tegra_powergate_partition(id);
50}
51
52static void do_unpowergate_locked(int id)
53{
54 if (id != -1)
55 tegra_unpowergate_partition(id);
56}
57
58void nvhost_module_reset(struct nvhost_device *dev)
59{
60 dev_dbg(&dev->dev,
61 "%s: asserting %s module reset (id %d, id2 %d)\n",
62 __func__, dev->name,
63 dev->powergate_ids[0], dev->powergate_ids[1]);
64
65 mutex_lock(&dev->lock);
66
67 /* assert module and mc client reset */
68 if (dev->powergate_ids[0] != -1) {
69 tegra_powergate_mc_disable(dev->powergate_ids[0]);
70 tegra_periph_reset_assert(dev->clk[0]);
71 tegra_powergate_mc_flush(dev->powergate_ids[0]);
72 }
73 if (dev->powergate_ids[1] != -1) {
74 tegra_powergate_mc_disable(dev->powergate_ids[1]);
75 tegra_periph_reset_assert(dev->clk[1]);
76 tegra_powergate_mc_flush(dev->powergate_ids[1]);
77 }
78
79 udelay(POWERGATE_DELAY);
80
81 /* deassert reset */
82 if (dev->powergate_ids[0] != -1) {
83 tegra_powergate_mc_flush_done(dev->powergate_ids[0]);
84 tegra_periph_reset_deassert(dev->clk[0]);
85 tegra_powergate_mc_enable(dev->powergate_ids[0]);
86 }
87 if (dev->powergate_ids[1] != -1) {
88 tegra_powergate_mc_flush_done(dev->powergate_ids[1]);
89 tegra_periph_reset_deassert(dev->clk[1]);
90 tegra_powergate_mc_enable(dev->powergate_ids[1]);
91 }
92
93 mutex_unlock(&dev->lock);
94
95 dev_dbg(&dev->dev, "%s: module %s out of reset\n",
96 __func__, dev->name);
97}
98
99static void to_state_clockgated_locked(struct nvhost_device *dev)
100{
101 if (dev->powerstate == NVHOST_POWER_STATE_RUNNING) {
102 int i;
103 for (i = 0; i < dev->num_clks; i++)
104 clk_disable(dev->clk[i]);
105 if (dev->dev.parent)
106 nvhost_module_idle(to_nvhost_device(dev->dev.parent));
107 } else if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED
108 && dev->can_powergate) {
109 do_unpowergate_locked(dev->powergate_ids[0]);
110 do_unpowergate_locked(dev->powergate_ids[1]);
111 }
112 dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED;
113}
114
115static void to_state_running_locked(struct nvhost_device *dev)
116{
117 int prev_state = dev->powerstate;
118 if (dev->powerstate == NVHOST_POWER_STATE_POWERGATED)
119 to_state_clockgated_locked(dev);
120 if (dev->powerstate == NVHOST_POWER_STATE_CLOCKGATED) {
121 int i;
122
123 if (dev->dev.parent)
124 nvhost_module_busy(to_nvhost_device(dev->dev.parent));
125
126 for (i = 0; i < dev->num_clks; i++) {
127 int err = clk_enable(dev->clk[i]);
128 BUG_ON(err);
129 }
130
131 if (prev_state == NVHOST_POWER_STATE_POWERGATED
132 && dev->finalize_poweron)
133 dev->finalize_poweron(dev);
134 }
135 dev->powerstate = NVHOST_POWER_STATE_RUNNING;
136}
137
138/* This gets called from powergate_handler() and from module suspend.
139 * Module suspend is done for all modules, runtime power gating only
140 * for modules with can_powergate set.
141 */
142static int to_state_powergated_locked(struct nvhost_device *dev)
143{
144 int err = 0;
145
146 if (dev->prepare_poweroff
147 && dev->powerstate != NVHOST_POWER_STATE_POWERGATED) {
148 /* Clock needs to be on in prepare_poweroff */
149 to_state_running_locked(dev);
150 err = dev->prepare_poweroff(dev);
151 if (err)
152 return err;
153 }
154
155 if (dev->powerstate == NVHOST_POWER_STATE_RUNNING)
156 to_state_clockgated_locked(dev);
157
158 if (dev->can_powergate) {
159 do_powergate_locked(dev->powergate_ids[0]);
160 do_powergate_locked(dev->powergate_ids[1]);
161 }
162
163 dev->powerstate = NVHOST_POWER_STATE_POWERGATED;
164 return 0;
165}
166
167static void schedule_powergating_locked(struct nvhost_device *dev)
168{
169 if (dev->can_powergate)
170 schedule_delayed_work(&dev->powerstate_down,
171 msecs_to_jiffies(dev->powergate_delay));
172}
173
174static void schedule_clockgating_locked(struct nvhost_device *dev)
175{
176 schedule_delayed_work(&dev->powerstate_down,
177 msecs_to_jiffies(dev->clockgate_delay));
178}
179
180void nvhost_module_busy(struct nvhost_device *dev)
181{
182 if (dev->busy)
183 dev->busy(dev);
184
185 mutex_lock(&dev->lock);
186 cancel_delayed_work(&dev->powerstate_down);
187
188 dev->refcount++;
189 if (dev->refcount > 0 && !nvhost_module_powered(dev))
190 to_state_running_locked(dev);
191 mutex_unlock(&dev->lock);
192}
193
194static void powerstate_down_handler(struct work_struct *work)
195{
196 struct nvhost_device *dev;
197
198 dev = container_of(to_delayed_work(work),
199 struct nvhost_device,
200 powerstate_down);
201
202 mutex_lock(&dev->lock);
203 if (dev->refcount == 0) {
204 switch (dev->powerstate) {
205 case NVHOST_POWER_STATE_RUNNING:
206 to_state_clockgated_locked(dev);
207 schedule_powergating_locked(dev);
208 break;
209 case NVHOST_POWER_STATE_CLOCKGATED:
210 if (to_state_powergated_locked(dev))
211 schedule_powergating_locked(dev);
212 break;
213 default:
214 break;
215 }
216 }
217 mutex_unlock(&dev->lock);
218}
219
220
221void nvhost_module_idle_mult(struct nvhost_device *dev, int refs)
222{
223 bool kick = false;
224
225 mutex_lock(&dev->lock);
226 dev->refcount -= refs;
227 if (dev->refcount == 0) {
228 if (nvhost_module_powered(dev))
229 schedule_clockgating_locked(dev);
230 kick = true;
231 }
232 mutex_unlock(&dev->lock);
233
234 if (kick) {
235 wake_up(&dev->idle_wq);
236
237 if (dev->idle)
238 dev->idle(dev);
239 }
240}
241
242int nvhost_module_get_rate(struct nvhost_device *dev, unsigned long *rate,
243 int index)
244{
245 struct clk *c;
246
247 c = dev->clk[index];
248 if (IS_ERR_OR_NULL(c))
249 return -EINVAL;
250
251 /* Need to enable client to get correct rate */
252 nvhost_module_busy(dev);
253 *rate = clk_get_rate(c);
254 nvhost_module_idle(dev);
255 return 0;
256
257}
258
259static int nvhost_module_update_rate(struct nvhost_device *dev, int index)
260{
261 unsigned long rate = 0;
262 struct nvhost_module_client *m;
263
264 if (!dev->clk[index])
265 return -EINVAL;
266
267 list_for_each_entry(m, &dev->client_list, node) {
268 rate = max(m->rate[index], rate);
269 }
270 if (!rate)
271 rate = clk_round_rate(dev->clk[index],
272 dev->clocks[index].default_rate);
273
274 return clk_set_rate(dev->clk[index], rate);
275}
276
277int nvhost_module_set_rate(struct nvhost_device *dev, void *priv,
278 unsigned long rate, int index)
279{
280 struct nvhost_module_client *m;
281 int i, ret = 0;
282
283 mutex_lock(&client_list_lock);
284 list_for_each_entry(m, &dev->client_list, node) {
285 if (m->priv == priv) {
286 for (i = 0; i < dev->num_clks; i++)
287 m->rate[i] = clk_round_rate(dev->clk[i], rate);
288 break;
289 }
290 }
291
292 for (i = 0; i < dev->num_clks; i++) {
293 ret = nvhost_module_update_rate(dev, i);
294 if (ret < 0)
295 break;
296 }
297 mutex_unlock(&client_list_lock);
298 return ret;
299
300}
301
302int nvhost_module_add_client(struct nvhost_device *dev, void *priv)
303{
304 int i;
305 unsigned long rate;
306 struct nvhost_module_client *client;
307
308 client = kzalloc(sizeof(*client), GFP_KERNEL);
309 if (!client)
310 return -ENOMEM;
311
312 INIT_LIST_HEAD(&client->node);
313 client->priv = priv;
314
315 for (i = 0; i < dev->num_clks; i++) {
316 rate = clk_round_rate(dev->clk[i],
317 dev->clocks[i].default_rate);
318 client->rate[i] = rate;
319 }
320 mutex_lock(&client_list_lock);
321 list_add_tail(&client->node, &dev->client_list);
322 mutex_unlock(&client_list_lock);
323 return 0;
324}
325
326void nvhost_module_remove_client(struct nvhost_device *dev, void *priv)
327{
328 int i;
329 struct nvhost_module_client *m;
330
331 mutex_lock(&client_list_lock);
332 list_for_each_entry(m, &dev->client_list, node) {
333 if (priv == m->priv) {
334 list_del(&m->node);
335 break;
336 }
337 }
338 if (m) {
339 kfree(m);
340 for (i = 0; i < dev->num_clks; i++)
341 nvhost_module_update_rate(dev, i);
342 }
343 mutex_unlock(&client_list_lock);
344}
345
346int nvhost_module_init(struct nvhost_device *dev)
347{
348 int i = 0;
349
350 /* initialize clocks to known state */
351 INIT_LIST_HEAD(&dev->client_list);
352 while (dev->clocks[i].name && i < NVHOST_MODULE_MAX_CLOCKS) {
353 char devname[MAX_DEVID_LENGTH];
354 long rate = dev->clocks[i].default_rate;
355 struct clk *c;
356
357 snprintf(devname, MAX_DEVID_LENGTH, "tegra_%s", dev->name);
358 c = clk_get_sys(devname, dev->clocks[i].name);
359 BUG_ON(IS_ERR_OR_NULL(c));
360
361 rate = clk_round_rate(c, rate);
362 clk_enable(c);
363 clk_set_rate(c, rate);
364 clk_disable(c);
365 dev->clk[i] = c;
366 i++;
367 }
368 dev->num_clks = i;
369
370 mutex_init(&dev->lock);
371 init_waitqueue_head(&dev->idle_wq);
372 INIT_DELAYED_WORK(&dev->powerstate_down, powerstate_down_handler);
373
374 /* power gate units that we can power gate */
375 if (dev->can_powergate) {
376 do_powergate_locked(dev->powergate_ids[0]);
377 do_powergate_locked(dev->powergate_ids[1]);
378 dev->powerstate = NVHOST_POWER_STATE_POWERGATED;
379 } else {
380 do_unpowergate_locked(dev->powergate_ids[0]);
381 do_unpowergate_locked(dev->powergate_ids[1]);
382 dev->powerstate = NVHOST_POWER_STATE_CLOCKGATED;
383 }
384
385 return 0;
386}
387
388static int is_module_idle(struct nvhost_device *dev)
389{
390 int count;
391 mutex_lock(&dev->lock);
392 count = dev->refcount;
393 mutex_unlock(&dev->lock);
394 return (count == 0);
395}
396
397static void debug_not_idle(struct nvhost_master *host)
398{
399 int i;
400 bool lock_released = true;
401
402 for (i = 0; i < host->nb_channels; i++) {
403 struct nvhost_device *dev = host->channels[i].dev;
404 mutex_lock(&dev->lock);
405 if (dev->name)
406 dev_warn(&host->dev->dev,
407 "tegra_grhost: %s: refcnt %d\n", dev->name,
408 dev->refcount);
409 mutex_unlock(&dev->lock);
410 }
411
412 for (i = 0; i < host->syncpt.nb_mlocks; i++) {
413 int c = atomic_read(&host->syncpt.lock_counts[i]);
414 if (c) {
415 dev_warn(&host->dev->dev,
416 "tegra_grhost: lock id %d: refcnt %d\n",
417 i, c);
418 lock_released = false;
419 }
420 }
421 if (lock_released)
422 dev_dbg(&host->dev->dev, "tegra_grhost: all locks released\n");
423}
424
425int nvhost_module_suspend(struct nvhost_device *dev, bool system_suspend)
426{
427 int ret;
428 struct nvhost_master *host = nvhost_get_host(dev);
429
430 if (system_suspend && !is_module_idle(dev))
431 debug_not_idle(host);
432
433 ret = wait_event_timeout(dev->idle_wq, is_module_idle(dev),
434 ACM_SUSPEND_WAIT_FOR_IDLE_TIMEOUT);
435 if (ret == 0) {
436 dev_info(&dev->dev, "%s prevented suspend\n",
437 dev->name);
438 return -EBUSY;
439 }
440
441 if (system_suspend)
442 dev_dbg(&dev->dev, "tegra_grhost: entered idle\n");
443
444 mutex_lock(&dev->lock);
445 cancel_delayed_work(&dev->powerstate_down);
446 to_state_powergated_locked(dev);
447 mutex_unlock(&dev->lock);
448
449 if (dev->suspend)
450 dev->suspend(dev);
451
452 return 0;
453}
454
455void nvhost_module_deinit(struct nvhost_device *dev)
456{
457 int i;
458
459 if (dev->deinit)
460 dev->deinit(dev);
461
462 nvhost_module_suspend(dev, false);
463 for (i = 0; i < dev->num_clks; i++)
464 clk_put(dev->clk[i]);
465 dev->powerstate = NVHOST_POWER_STATE_DEINIT;
466}
467
diff --git a/drivers/video/tegra/host/nvhost_acm.h b/drivers/video/tegra/host/nvhost_acm.h
new file mode 100644
index 00000000000..a12c0c3fa32
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_acm.h
@@ -0,0 +1,60 @@
1/*
2 * drivers/video/tegra/host/nvhost_acm.h
3 *
4 * Tegra Graphics Host Automatic Clock Management
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_ACM_H
22#define __NVHOST_ACM_H
23
24#include <linux/workqueue.h>
25#include <linux/wait.h>
26#include <linux/mutex.h>
27#include <linux/clk.h>
28#include <linux/nvhost.h>
29
30/* Sets clocks and powergating state for a module */
31int nvhost_module_init(struct nvhost_device *ndev);
32void nvhost_module_deinit(struct nvhost_device *dev);
33int nvhost_module_suspend(struct nvhost_device *dev, bool system_suspend);
34
35void nvhost_module_reset(struct nvhost_device *dev);
36void nvhost_module_busy(struct nvhost_device *dev);
37void nvhost_module_idle_mult(struct nvhost_device *dev, int refs);
38int nvhost_module_add_client(struct nvhost_device *dev,
39 void *priv);
40void nvhost_module_remove_client(struct nvhost_device *dev,
41 void *priv);
42int nvhost_module_get_rate(struct nvhost_device *dev,
43 unsigned long *rate,
44 int index);
45int nvhost_module_set_rate(struct nvhost_device *dev, void *priv,
46 unsigned long rate, int index);
47
48
49static inline bool nvhost_module_powered(struct nvhost_device *dev)
50{
51 return dev->powerstate == NVHOST_POWER_STATE_RUNNING;
52}
53
54static inline void nvhost_module_idle(struct nvhost_device *dev)
55{
56 nvhost_module_idle_mult(dev, 1);
57}
58
59
60#endif
diff --git a/drivers/video/tegra/host/nvhost_cdma.c b/drivers/video/tegra/host/nvhost_cdma.c
new file mode 100644
index 00000000000..775d761e65c
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_cdma.c
@@ -0,0 +1,508 @@
1/*
2 * drivers/video/tegra/host/nvhost_cdma.c
3 *
4 * Tegra Graphics Host Command DMA
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_cdma.h"
22#include "dev.h"
23#include <asm/cacheflush.h>
24
25#include <linux/slab.h>
26#include <linux/kfifo.h>
27#include <trace/events/nvhost.h>
28#include <linux/interrupt.h>
29
30/*
31 * TODO:
32 * stats
33 * - for figuring out what to optimize further
34 * resizable push buffer
35 * - some channels hardly need any, some channels (3d) could use more
36 */
37
38/**
39 * Add an entry to the sync queue.
40 */
41static void add_to_sync_queue(struct nvhost_cdma *cdma,
42 struct nvhost_job *job,
43 u32 nr_slots,
44 u32 first_get)
45{
46 BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
47
48 job->first_get = first_get;
49 job->num_slots = nr_slots;
50 nvhost_job_get(job);
51 list_add_tail(&job->list, &cdma->sync_queue);
52}
53
54/**
55 * Return the status of the cdma's sync queue or push buffer for the given event
56 * - sq empty: returns 1 for empty, 0 for not empty (as in "1 empty queue" :-)
57 * - pb space: returns the number of free slots in the channel's push buffer
58 * Must be called with the cdma lock held.
59 */
60static unsigned int cdma_status_locked(struct nvhost_cdma *cdma,
61 enum cdma_event event)
62{
63 switch (event) {
64 case CDMA_EVENT_SYNC_QUEUE_EMPTY:
65 return list_empty(&cdma->sync_queue) ? 1 : 0;
66 case CDMA_EVENT_PUSH_BUFFER_SPACE: {
67 struct push_buffer *pb = &cdma->push_buffer;
68 BUG_ON(!cdma_pb_op(cdma).space);
69 return cdma_pb_op(cdma).space(pb);
70 }
71 default:
72 return 0;
73 }
74}
75
76/**
77 * Sleep (if necessary) until the requested event happens
78 * - CDMA_EVENT_SYNC_QUEUE_EMPTY : sync queue is completely empty.
79 * - Returns 1
80 * - CDMA_EVENT_PUSH_BUFFER_SPACE : there is space in the push buffer
81 * - Return the amount of space (> 0)
82 * Must be called with the cdma lock held.
83 */
84unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
85 enum cdma_event event)
86{
87 for (;;) {
88 unsigned int space = cdma_status_locked(cdma, event);
89 if (space)
90 return space;
91
92 trace_nvhost_wait_cdma(cdma_to_channel(cdma)->dev->name,
93 event);
94
95 BUG_ON(cdma->event != CDMA_EVENT_NONE);
96 cdma->event = event;
97
98 mutex_unlock(&cdma->lock);
99 down(&cdma->sem);
100 mutex_lock(&cdma->lock);
101 }
102 return 0;
103}
104
105/**
106 * Start timer for a buffer submition that has completed yet.
107 * Must be called with the cdma lock held.
108 */
109static void cdma_start_timer_locked(struct nvhost_cdma *cdma,
110 struct nvhost_job *job)
111{
112 BUG_ON(!job);
113 if (cdma->timeout.clientid) {
114 /* timer already started */
115 return;
116 }
117
118 cdma->timeout.ctx = job->hwctx;
119 cdma->timeout.clientid = job->clientid;
120 cdma->timeout.syncpt_id = job->syncpt_id;
121 cdma->timeout.syncpt_val = job->syncpt_end;
122 cdma->timeout.start_ktime = ktime_get();
123
124 schedule_delayed_work(&cdma->timeout.wq,
125 msecs_to_jiffies(job->timeout));
126}
127
128/**
129 * Stop timer when a buffer submition completes.
130 * Must be called with the cdma lock held.
131 */
132static void stop_cdma_timer_locked(struct nvhost_cdma *cdma)
133{
134 cancel_delayed_work(&cdma->timeout.wq);
135 cdma->timeout.ctx = NULL;
136 cdma->timeout.clientid = 0;
137}
138
139/**
140 * For all sync queue entries that have already finished according to the
141 * current sync point registers:
142 * - unpin & unref their mems
143 * - pop their push buffer slots
144 * - remove them from the sync queue
145 * This is normally called from the host code's worker thread, but can be
146 * called manually if necessary.
147 * Must be called with the cdma lock held.
148 */
149static void update_cdma_locked(struct nvhost_cdma *cdma)
150{
151 bool signal = false;
152 struct nvhost_master *dev = cdma_to_dev(cdma);
153 struct nvhost_syncpt *sp = &dev->syncpt;
154 struct nvhost_job *job, *n;
155
156 BUG_ON(!cdma->running);
157
158 /*
159 * Walk the sync queue, reading the sync point registers as necessary,
160 * to consume as many sync queue entries as possible without blocking
161 */
162 list_for_each_entry_safe(job, n, &cdma->sync_queue, list) {
163 BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
164
165 /* Check whether this syncpt has completed, and bail if not */
166 if (!nvhost_syncpt_is_expired(sp,
167 job->syncpt_id, job->syncpt_end)) {
168 /* Start timer on next pending syncpt */
169 if (job->timeout)
170 cdma_start_timer_locked(cdma, job);
171 break;
172 }
173
174 /* Cancel timeout, when a buffer completes */
175 if (cdma->timeout.clientid)
176 stop_cdma_timer_locked(cdma);
177
178 /* Unpin the memory */
179 nvhost_job_unpin(job);
180
181 /* Pop push buffer slots */
182 if (job->num_slots) {
183 struct push_buffer *pb = &cdma->push_buffer;
184 BUG_ON(!cdma_pb_op(cdma).pop_from);
185 cdma_pb_op(cdma).pop_from(pb, job->num_slots);
186 if (cdma->event == CDMA_EVENT_PUSH_BUFFER_SPACE)
187 signal = true;
188 }
189
190 list_del(&job->list);
191 nvhost_job_put(job);
192 }
193
194 if (list_empty(&cdma->sync_queue) &&
195 cdma->event == CDMA_EVENT_SYNC_QUEUE_EMPTY)
196 signal = true;
197
198 /* Wake up CdmaWait() if the requested event happened */
199 if (signal) {
200 cdma->event = CDMA_EVENT_NONE;
201 up(&cdma->sem);
202 }
203}
204
205void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
206 struct nvhost_syncpt *syncpt, struct device *dev)
207{
208 u32 get_restart;
209 u32 syncpt_incrs;
210 bool exec_ctxsave;
211 struct nvhost_job *job = NULL;
212 u32 syncpt_val;
213
214 syncpt_val = nvhost_syncpt_update_min(syncpt, cdma->timeout.syncpt_id);
215
216 dev_dbg(dev,
217 "%s: starting cleanup (thresh %d)\n",
218 __func__, syncpt_val);
219
220 /*
221 * Move the sync_queue read pointer to the first entry that hasn't
222 * completed based on the current HW syncpt value. It's likely there
223 * won't be any (i.e. we're still at the head), but covers the case
224 * where a syncpt incr happens just prior/during the teardown.
225 */
226
227 dev_dbg(dev,
228 "%s: skip completed buffers still in sync_queue\n",
229 __func__);
230
231 list_for_each_entry(job, &cdma->sync_queue, list) {
232 if (syncpt_val < job->syncpt_end)
233 break;
234
235 nvhost_job_dump(dev, job);
236 }
237
238 /*
239 * Walk the sync_queue, first incrementing with the CPU syncpts that
240 * are partially executed (the first buffer) or fully skipped while
241 * still in the current context (slots are also NOP-ed).
242 *
243 * At the point contexts are interleaved, syncpt increments must be
244 * done inline with the pushbuffer from a GATHER buffer to maintain
245 * the order (slots are modified to be a GATHER of syncpt incrs).
246 *
247 * Note: save in get_restart the location where the timed out buffer
248 * started in the PB, so we can start the refetch from there (with the
249 * modified NOP-ed PB slots). This lets things appear to have completed
250 * properly for this buffer and resources are freed.
251 */
252
253 dev_dbg(dev,
254 "%s: perform CPU incr on pending same ctx buffers\n",
255 __func__);
256
257 get_restart = cdma->last_put;
258 if (!list_empty(&cdma->sync_queue))
259 get_restart = job->first_get;
260
261 /* do CPU increments as long as this context continues */
262 list_for_each_entry_from(job, &cdma->sync_queue, list) {
263 /* different context, gets us out of this loop */
264 if (job->clientid != cdma->timeout.clientid)
265 break;
266
267 /* won't need a timeout when replayed */
268 job->timeout = 0;
269
270 syncpt_incrs = job->syncpt_end - syncpt_val;
271 dev_dbg(dev,
272 "%s: CPU incr (%d)\n", __func__, syncpt_incrs);
273
274 nvhost_job_dump(dev, job);
275
276 /* safe to use CPU to incr syncpts */
277 cdma_op(cdma).timeout_cpu_incr(cdma,
278 job->first_get,
279 syncpt_incrs,
280 job->syncpt_end,
281 job->num_slots);
282
283 syncpt_val += syncpt_incrs;
284 }
285
286 dev_dbg(dev,
287 "%s: GPU incr blocked interleaved ctx buffers\n",
288 __func__);
289
290 exec_ctxsave = false;
291
292 /* setup GPU increments */
293 list_for_each_entry_from(job, &cdma->sync_queue, list) {
294 /* same context, increment in the pushbuffer */
295 if (job->clientid == cdma->timeout.clientid) {
296 /* won't need a timeout when replayed */
297 job->timeout = 0;
298
299 /* update buffer's syncpts in the pushbuffer */
300 cdma_op(cdma).timeout_pb_incr(cdma,
301 job->first_get,
302 job->syncpt_incrs,
303 job->num_slots,
304 exec_ctxsave);
305
306 exec_ctxsave = false;
307 } else {
308 dev_dbg(dev,
309 "%s: switch to a different userctx\n",
310 __func__);
311 /*
312 * If previous context was the timed out context
313 * then clear its CTXSAVE in this slot.
314 */
315 exec_ctxsave = true;
316 }
317
318 nvhost_job_dump(dev, job);
319 }
320
321 dev_dbg(dev,
322 "%s: finished sync_queue modification\n", __func__);
323
324 /* roll back DMAGET and start up channel again */
325 cdma_op(cdma).timeout_teardown_end(cdma, get_restart);
326
327 if (cdma->timeout.ctx)
328 cdma->timeout.ctx->has_timedout = true;
329}
330
331/**
332 * Create a cdma
333 */
334int nvhost_cdma_init(struct nvhost_cdma *cdma)
335{
336 int err;
337 struct push_buffer *pb = &cdma->push_buffer;
338 BUG_ON(!cdma_pb_op(cdma).init);
339 mutex_init(&cdma->lock);
340 sema_init(&cdma->sem, 0);
341
342 INIT_LIST_HEAD(&cdma->sync_queue);
343
344 cdma->event = CDMA_EVENT_NONE;
345 cdma->running = false;
346 cdma->torndown = false;
347
348 err = cdma_pb_op(cdma).init(pb);
349 if (err)
350 return err;
351 return 0;
352}
353
354/**
355 * Destroy a cdma
356 */
357void nvhost_cdma_deinit(struct nvhost_cdma *cdma)
358{
359 struct push_buffer *pb = &cdma->push_buffer;
360
361 BUG_ON(!cdma_pb_op(cdma).destroy);
362 BUG_ON(cdma->running);
363 cdma_pb_op(cdma).destroy(pb);
364 cdma_op(cdma).timeout_destroy(cdma);
365}
366
367/**
368 * Begin a cdma submit
369 */
370int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job)
371{
372 mutex_lock(&cdma->lock);
373
374 if (job->timeout) {
375 /* init state on first submit with timeout value */
376 if (!cdma->timeout.initialized) {
377 int err;
378 BUG_ON(!cdma_op(cdma).timeout_init);
379 err = cdma_op(cdma).timeout_init(cdma,
380 job->syncpt_id);
381 if (err) {
382 mutex_unlock(&cdma->lock);
383 return err;
384 }
385 }
386 }
387 if (!cdma->running) {
388 BUG_ON(!cdma_op(cdma).start);
389 cdma_op(cdma).start(cdma);
390 }
391 cdma->slots_free = 0;
392 cdma->slots_used = 0;
393 cdma->first_get = cdma_pb_op(cdma).putptr(&cdma->push_buffer);
394 return 0;
395}
396
397/**
398 * Push two words into a push buffer slot
399 * Blocks as necessary if the push buffer is full.
400 */
401void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2)
402{
403 nvhost_cdma_push_gather(cdma, NULL, NULL, op1, op2);
404}
405
406/**
407 * Push two words into a push buffer slot
408 * Blocks as necessary if the push buffer is full.
409 */
410void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
411 struct nvmap_client *client,
412 struct nvmap_handle *handle, u32 op1, u32 op2)
413{
414 u32 slots_free = cdma->slots_free;
415 struct push_buffer *pb = &cdma->push_buffer;
416 BUG_ON(!cdma_pb_op(cdma).push_to);
417 BUG_ON(!cdma_op(cdma).kick);
418 if (slots_free == 0) {
419 cdma_op(cdma).kick(cdma);
420 slots_free = nvhost_cdma_wait_locked(cdma,
421 CDMA_EVENT_PUSH_BUFFER_SPACE);
422 }
423 cdma->slots_free = slots_free - 1;
424 cdma->slots_used++;
425 cdma_pb_op(cdma).push_to(pb, client, handle, op1, op2);
426}
427
428/**
429 * End a cdma submit
430 * Kick off DMA, add job to the sync queue, and a number of slots to be freed
431 * from the pushbuffer. The handles for a submit must all be pinned at the same
432 * time, but they can be unpinned in smaller chunks.
433 */
434void nvhost_cdma_end(struct nvhost_cdma *cdma,
435 struct nvhost_job *job)
436{
437 bool was_idle = list_empty(&cdma->sync_queue);
438
439 BUG_ON(!cdma_op(cdma).kick);
440 cdma_op(cdma).kick(cdma);
441
442 BUG_ON(job->syncpt_id == NVSYNCPT_INVALID);
443
444 add_to_sync_queue(cdma,
445 job,
446 cdma->slots_used,
447 cdma->first_get);
448
449 /* start timer on idle -> active transitions */
450 if (job->timeout && was_idle)
451 cdma_start_timer_locked(cdma, job);
452
453 mutex_unlock(&cdma->lock);
454}
455
456/**
457 * Update cdma state according to current sync point values
458 */
459void nvhost_cdma_update(struct nvhost_cdma *cdma)
460{
461 mutex_lock(&cdma->lock);
462 update_cdma_locked(cdma);
463 mutex_unlock(&cdma->lock);
464}
465
466/**
467 * Wait for push buffer to be empty.
468 * @cdma pointer to channel cdma
469 * @timeout timeout in ms
470 * Returns -ETIME if timeout was reached, zero if push buffer is empty.
471 */
472int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout)
473{
474 unsigned int space, err = 0;
475 unsigned long end_jiffies = jiffies + msecs_to_jiffies(timeout);
476
477 /*
478 * Wait for at most timeout ms. Recalculate timeout at each iteration
479 * to better keep within given timeout.
480 */
481 while(!err && time_before(jiffies, end_jiffies)) {
482 int timeout_jiffies = end_jiffies - jiffies;
483
484 mutex_lock(&cdma->lock);
485 space = cdma_status_locked(cdma,
486 CDMA_EVENT_SYNC_QUEUE_EMPTY);
487 if (space) {
488 mutex_unlock(&cdma->lock);
489 return 0;
490 }
491
492 /*
493 * Wait for sync queue to become empty. If there is already
494 * an event pending, we need to poll.
495 */
496 if (cdma->event != CDMA_EVENT_NONE) {
497 mutex_unlock(&cdma->lock);
498 schedule();
499 } else {
500 cdma->event = CDMA_EVENT_SYNC_QUEUE_EMPTY;
501
502 mutex_unlock(&cdma->lock);
503 err = down_timeout(&cdma->sem,
504 jiffies_to_msecs(timeout_jiffies));
505 }
506 }
507 return err;
508}
diff --git a/drivers/video/tegra/host/nvhost_cdma.h b/drivers/video/tegra/host/nvhost_cdma.h
new file mode 100644
index 00000000000..9cb9b827725
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_cdma.h
@@ -0,0 +1,133 @@
1/*
2 * drivers/video/tegra/host/nvhost_cdma.h
3 *
4 * Tegra Graphics Host Command DMA
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_CDMA_H
22#define __NVHOST_CDMA_H
23
24#include <linux/sched.h>
25#include <linux/semaphore.h>
26
27#include <linux/nvhost.h>
28#include <mach/nvmap.h>
29#include <linux/list.h>
30
31#include "nvhost_acm.h"
32
33struct nvhost_syncpt;
34struct nvhost_userctx_timeout;
35struct nvhost_job;
36
37/*
38 * cdma
39 *
40 * This is in charge of a host command DMA channel.
41 * Sends ops to a push buffer, and takes responsibility for unpinning
42 * (& possibly freeing) of memory after those ops have completed.
43 * Producer:
44 * begin
45 * push - send ops to the push buffer
46 * end - start command DMA and enqueue handles to be unpinned
47 * Consumer:
48 * update - call to update sync queue and push buffer, unpin memory
49 */
50
51struct nvmap_client_handle {
52 struct nvmap_client *client;
53 struct nvmap_handle *handle;
54};
55
56struct push_buffer {
57 struct nvmap_handle_ref *mem; /* handle to pushbuffer memory */
58 u32 *mapped; /* mapped pushbuffer memory */
59 u32 phys; /* physical address of pushbuffer */
60 u32 fence; /* index we've written */
61 u32 cur; /* index to write to */
62 struct nvmap_client_handle *nvmap;
63 /* nvmap handle for each opcode pair */
64};
65
66struct syncpt_buffer {
67 struct nvmap_handle_ref *mem; /* handle to pushbuffer memory */
68 u32 *mapped; /* mapped gather buffer (at channel offset */
69 u32 phys; /* physical address (at channel offset) */
70 u32 incr_per_buffer; /* max # of incrs per GATHER */
71 u32 words_per_incr; /* # of DWORDS in buffer to incr a syncpt */
72};
73
74struct buffer_timeout {
75 struct delayed_work wq; /* work queue */
76 bool initialized; /* timer one-time setup flag */
77 u32 syncpt_id; /* buffer completion syncpt id */
78 u32 syncpt_val; /* syncpt value when completed */
79 ktime_t start_ktime; /* starting time */
80 /* context timeout information */
81 struct nvhost_hwctx *ctx;
82 int clientid;
83};
84
85enum cdma_event {
86 CDMA_EVENT_NONE, /* not waiting for any event */
87 CDMA_EVENT_SYNC_QUEUE_EMPTY, /* wait for empty sync queue */
88 CDMA_EVENT_PUSH_BUFFER_SPACE /* wait for space in push buffer */
89};
90
91struct nvhost_cdma {
92 struct mutex lock; /* controls access to shared state */
93 struct semaphore sem; /* signalled when event occurs */
94 enum cdma_event event; /* event that sem is waiting for */
95 unsigned int slots_used; /* pb slots used in current submit */
96 unsigned int slots_free; /* pb slots free in current submit */
97 unsigned int first_get; /* DMAGET value, where submit begins */
98 unsigned int last_put; /* last value written to DMAPUT */
99 struct push_buffer push_buffer; /* channel's push buffer */
100 struct syncpt_buffer syncpt_buffer; /* syncpt incr buffer */
101 struct list_head sync_queue; /* job queue */
102 struct buffer_timeout timeout; /* channel's timeout state/wq */
103 bool running;
104 bool torndown;
105};
106
107#define cdma_to_channel(cdma) container_of(cdma, struct nvhost_channel, cdma)
108#define cdma_to_dev(cdma) nvhost_get_host(cdma_to_channel(cdma)->dev)
109#define cdma_op(cdma) (cdma_to_dev(cdma)->op.cdma)
110#define cdma_to_nvmap(cdma) ((cdma_to_dev(cdma))->nvmap)
111#define pb_to_cdma(pb) container_of(pb, struct nvhost_cdma, push_buffer)
112#define cdma_pb_op(cdma) (cdma_to_dev(cdma)->op.push_buffer)
113
114int nvhost_cdma_init(struct nvhost_cdma *cdma);
115void nvhost_cdma_deinit(struct nvhost_cdma *cdma);
116void nvhost_cdma_stop(struct nvhost_cdma *cdma);
117int nvhost_cdma_begin(struct nvhost_cdma *cdma, struct nvhost_job *job);
118void nvhost_cdma_push(struct nvhost_cdma *cdma, u32 op1, u32 op2);
119#define NVHOST_CDMA_PUSH_GATHER_CTXSAVE 0xffffffff
120void nvhost_cdma_push_gather(struct nvhost_cdma *cdma,
121 struct nvmap_client *client,
122 struct nvmap_handle *handle, u32 op1, u32 op2);
123void nvhost_cdma_end(struct nvhost_cdma *cdma,
124 struct nvhost_job *job);
125void nvhost_cdma_update(struct nvhost_cdma *cdma);
126int nvhost_cdma_flush(struct nvhost_cdma *cdma, int timeout);
127void nvhost_cdma_peek(struct nvhost_cdma *cdma,
128 u32 dmaget, int slot, u32 *out);
129unsigned int nvhost_cdma_wait_locked(struct nvhost_cdma *cdma,
130 enum cdma_event event);
131void nvhost_cdma_update_sync_queue(struct nvhost_cdma *cdma,
132 struct nvhost_syncpt *syncpt, struct device *dev);
133#endif
diff --git a/drivers/video/tegra/host/nvhost_channel.c b/drivers/video/tegra/host/nvhost_channel.c
new file mode 100644
index 00000000000..a7c03308134
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_channel.c
@@ -0,0 +1,158 @@
1/*
2 * drivers/video/tegra/host/nvhost_channel.c
3 *
4 * Tegra Graphics Host Channel
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_channel.h"
22#include "dev.h"
23#include "nvhost_job.h"
24#include <trace/events/nvhost.h>
25#include <linux/nvhost_ioctl.h>
26#include <linux/slab.h>
27
28#include <linux/platform_device.h>
29
30#define NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT 50
31
32int nvhost_channel_init(struct nvhost_channel *ch,
33 struct nvhost_master *dev, int index)
34{
35 int err;
36 struct nvhost_device *ndev;
37 struct resource *r = NULL;
38 void __iomem *regs = NULL;
39 struct resource *reg_mem = NULL;
40
41 /* Link nvhost_device to nvhost_channel */
42 err = host_channel_op(dev).init(ch, dev, index);
43 if (err < 0) {
44 dev_err(&dev->dev->dev, "failed to init channel %d\n",
45 index);
46 return err;
47 }
48 ndev = ch->dev;
49 ndev->channel = ch;
50
51 /* Map IO memory related to nvhost_device */
52 if (ndev->moduleid != NVHOST_MODULE_NONE) {
53 /* First one is host1x - skip that */
54 r = nvhost_get_resource(dev->dev,
55 IORESOURCE_MEM, ndev->moduleid + 1);
56 if (!r)
57 goto fail;
58
59 reg_mem = request_mem_region(r->start,
60 resource_size(r), ndev->name);
61 if (!reg_mem)
62 goto fail;
63
64 regs = ioremap(r->start, resource_size(r));
65 if (!regs)
66 goto fail;
67
68 ndev->reg_mem = reg_mem;
69 ndev->aperture = regs;
70 }
71 return 0;
72
73fail:
74 if (reg_mem)
75 release_mem_region(r->start, resource_size(r));
76 if (regs)
77 iounmap(regs);
78 dev_err(&ndev->dev, "failed to get register memory\n");
79 return -ENXIO;
80
81}
82
83int nvhost_channel_submit(struct nvhost_job *job)
84{
85 /* Low priority submits wait until sync queue is empty. Ignores result
86 * from nvhost_cdma_flush, as we submit either when push buffer is
87 * empty or when we reach the timeout. */
88 if (job->priority < NVHOST_PRIORITY_MEDIUM)
89 (void)nvhost_cdma_flush(&job->ch->cdma,
90 NVHOST_CHANNEL_LOW_PRIO_MAX_WAIT);
91
92 return channel_op(job->ch).submit(job);
93}
94
95struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch)
96{
97 int err = 0;
98 mutex_lock(&ch->reflock);
99 if (ch->refcount == 0) {
100 if (ch->dev->init)
101 ch->dev->init(ch->dev);
102 err = nvhost_cdma_init(&ch->cdma);
103 } else if (ch->dev->exclusive) {
104 err = -EBUSY;
105 }
106 if (!err)
107 ch->refcount++;
108
109 mutex_unlock(&ch->reflock);
110
111 /* Keep alive modules that needs to be when a channel is open */
112 if (!err && ch->dev->keepalive)
113 nvhost_module_busy(ch->dev);
114
115 return err ? NULL : ch;
116}
117
118void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx)
119{
120 BUG_ON(!channel_cdma_op(ch).stop);
121
122 if (ctx) {
123 mutex_lock(&ch->submitlock);
124 if (ch->cur_ctx == ctx)
125 ch->cur_ctx = NULL;
126 mutex_unlock(&ch->submitlock);
127 }
128
129 /* Allow keep-alive'd module to be turned off */
130 if (ch->dev->keepalive)
131 nvhost_module_idle(ch->dev);
132
133 mutex_lock(&ch->reflock);
134 if (ch->refcount == 1) {
135 channel_cdma_op(ch).stop(&ch->cdma);
136 nvhost_cdma_deinit(&ch->cdma);
137 nvhost_module_suspend(ch->dev, false);
138 }
139 ch->refcount--;
140 mutex_unlock(&ch->reflock);
141}
142
143int nvhost_channel_suspend(struct nvhost_channel *ch)
144{
145 int ret = 0;
146
147 mutex_lock(&ch->reflock);
148 BUG_ON(!channel_cdma_op(ch).stop);
149
150 if (ch->refcount) {
151 ret = nvhost_module_suspend(ch->dev, false);
152 if (!ret)
153 channel_cdma_op(ch).stop(&ch->cdma);
154 }
155 mutex_unlock(&ch->reflock);
156
157 return ret;
158}
diff --git a/drivers/video/tegra/host/nvhost_channel.h b/drivers/video/tegra/host/nvhost_channel.h
new file mode 100644
index 00000000000..7b946c8ee85
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_channel.h
@@ -0,0 +1,86 @@
1/*
2 * drivers/video/tegra/host/nvhost_channel.h
3 *
4 * Tegra Graphics Host Channel
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_CHANNEL_H
22#define __NVHOST_CHANNEL_H
23
24#include "nvhost_cdma.h"
25#include "nvhost_acm.h"
26#include "nvhost_hwctx.h"
27#include "nvhost_job.h"
28
29#include <linux/cdev.h>
30#include <linux/io.h>
31
32#define NVHOST_MAX_WAIT_CHECKS 256
33#define NVHOST_MAX_GATHERS 512
34#define NVHOST_MAX_HANDLES 1280
35#define NVHOST_MAX_POWERGATE_IDS 2
36
37struct nvhost_master;
38struct nvhost_waitchk;
39struct nvhost_device;
40
41struct nvhost_channel_gather {
42 u32 words;
43 phys_addr_t mem;
44 u32 mem_id;
45 int offset;
46};
47
48struct nvhost_channel {
49 int refcount;
50 int chid;
51 u32 syncpt_id;
52 struct mutex reflock;
53 struct mutex submitlock;
54 void __iomem *aperture;
55 struct nvhost_hwctx *cur_ctx;
56 struct device *node;
57 struct nvhost_device *dev;
58 struct cdev cdev;
59 struct nvhost_hwctx_handler *ctxhandler;
60 struct nvhost_cdma cdma;
61};
62
63int nvhost_channel_init(
64 struct nvhost_channel *ch,
65 struct nvhost_master *dev, int index);
66
67int nvhost_channel_submit(struct nvhost_job *job);
68
69struct nvhost_channel *nvhost_getchannel(struct nvhost_channel *ch);
70void nvhost_putchannel(struct nvhost_channel *ch, struct nvhost_hwctx *ctx);
71int nvhost_channel_suspend(struct nvhost_channel *ch);
72
73#define channel_cdma_op(ch) (nvhost_get_host(ch->dev)->op.cdma)
74#define channel_op(ch) (nvhost_get_host(ch->dev)->op.channel)
75#define host_channel_op(host) (host->op.channel)
76
77int nvhost_channel_drain_read_fifo(void __iomem *chan_regs,
78 u32 *ptr, unsigned int count, unsigned int *pending);
79
80int nvhost_channel_read_3d_reg(
81 struct nvhost_channel *channel,
82 struct nvhost_hwctx *hwctx,
83 u32 offset,
84 u32 *value);
85
86#endif
diff --git a/drivers/video/tegra/host/nvhost_hwctx.h b/drivers/video/tegra/host/nvhost_hwctx.h
new file mode 100644
index 00000000000..02a3976f01c
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_hwctx.h
@@ -0,0 +1,67 @@
1/*
2 * drivers/video/tegra/host/nvhost_hwctx.h
3 *
4 * Tegra Graphics Host Hardware Context Interface
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_HWCTX_H
22#define __NVHOST_HWCTX_H
23
24#include <linux/string.h>
25#include <linux/kref.h>
26
27#include <linux/nvhost.h>
28#include <mach/nvmap.h>
29
30struct nvhost_channel;
31struct nvhost_cdma;
32
33struct nvhost_hwctx {
34 struct kref ref;
35 struct nvhost_hwctx_handler *h;
36 struct nvhost_channel *channel;
37 bool valid;
38 bool has_timedout;
39};
40
41struct nvhost_hwctx_handler {
42 struct nvhost_hwctx * (*alloc) (struct nvhost_hwctx_handler *h,
43 struct nvhost_channel *ch);
44 void (*get) (struct nvhost_hwctx *ctx);
45 void (*put) (struct nvhost_hwctx *ctx);
46 void (*save_push) (struct nvhost_hwctx *ctx,
47 struct nvhost_cdma *cdma);
48 void (*save_service) (struct nvhost_hwctx *ctx);
49 void *priv;
50};
51
52
53struct hwctx_reginfo {
54 unsigned int offset:12;
55 unsigned int count:16;
56 unsigned int type:2;
57};
58
59enum {
60 HWCTX_REGINFO_DIRECT = 0,
61 HWCTX_REGINFO_INDIRECT,
62 HWCTX_REGINFO_INDIRECT_4X
63};
64
65#define HWCTX_REGINFO(offset, count, type) {offset, count, HWCTX_REGINFO_##type}
66
67#endif
diff --git a/drivers/video/tegra/host/nvhost_intr.c b/drivers/video/tegra/host/nvhost_intr.c
new file mode 100644
index 00000000000..7c4bdc7bafb
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_intr.c
@@ -0,0 +1,428 @@
1/*
2 * drivers/video/tegra/host/nvhost_intr.c
3 *
4 * Tegra Graphics Host Interrupt Management
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "nvhost_intr.h"
22#include "dev.h"
23#include <linux/interrupt.h>
24#include <linux/slab.h>
25#include <linux/irq.h>
26#include <trace/events/nvhost.h>
27
28
29
30
31
32/*** Wait list management ***/
33
34struct nvhost_waitlist {
35 struct list_head list;
36 struct kref refcount;
37 u32 thresh;
38 enum nvhost_intr_action action;
39 atomic_t state;
40 void *data;
41 int count;
42};
43
44enum waitlist_state {
45 WLS_PENDING,
46 WLS_REMOVED,
47 WLS_CANCELLED,
48 WLS_HANDLED
49};
50
51static void waiter_release(struct kref *kref)
52{
53 kfree(container_of(kref, struct nvhost_waitlist, refcount));
54}
55
56/**
57 * add a waiter to a waiter queue, sorted by threshold
58 * returns true if it was added at the head of the queue
59 */
60static bool add_waiter_to_queue(struct nvhost_waitlist *waiter,
61 struct list_head *queue)
62{
63 struct nvhost_waitlist *pos;
64 u32 thresh = waiter->thresh;
65
66 list_for_each_entry_reverse(pos, queue, list)
67 if ((s32)(pos->thresh - thresh) <= 0) {
68 list_add(&waiter->list, &pos->list);
69 return false;
70 }
71
72 list_add(&waiter->list, queue);
73 return true;
74}
75
76/**
77 * run through a waiter queue for a single sync point ID
78 * and gather all completed waiters into lists by actions
79 */
80static void remove_completed_waiters(struct list_head *head, u32 sync,
81 struct list_head completed[NVHOST_INTR_ACTION_COUNT])
82{
83 struct list_head *dest;
84 struct nvhost_waitlist *waiter, *next, *prev;
85
86 list_for_each_entry_safe(waiter, next, head, list) {
87 if ((s32)(waiter->thresh - sync) > 0)
88 break;
89
90 dest = completed + waiter->action;
91
92 /* consolidate submit cleanups */
93 if (waiter->action == NVHOST_INTR_ACTION_SUBMIT_COMPLETE
94 && !list_empty(dest)) {
95 prev = list_entry(dest->prev,
96 struct nvhost_waitlist, list);
97 if (prev->data == waiter->data) {
98 prev->count++;
99 dest = NULL;
100 }
101 }
102
103 /* PENDING->REMOVED or CANCELLED->HANDLED */
104 if (atomic_inc_return(&waiter->state) == WLS_HANDLED || !dest) {
105 list_del(&waiter->list);
106 kref_put(&waiter->refcount, waiter_release);
107 } else {
108 list_move_tail(&waiter->list, dest);
109 }
110 }
111}
112
113void reset_threshold_interrupt(struct nvhost_intr *intr,
114 struct list_head *head,
115 unsigned int id)
116{
117 u32 thresh = list_first_entry(head,
118 struct nvhost_waitlist, list)->thresh;
119 BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
120 intr_op(intr).enable_syncpt_intr));
121
122 intr_op(intr).set_syncpt_threshold(intr, id, thresh);
123 intr_op(intr).enable_syncpt_intr(intr, id);
124}
125
126
127static void action_submit_complete(struct nvhost_waitlist *waiter)
128{
129 struct nvhost_channel *channel = waiter->data;
130 int nr_completed = waiter->count;
131
132 /* Add nr_completed to trace */
133 trace_nvhost_channel_submit_complete(channel->dev->name,
134 nr_completed, waiter->thresh);
135
136 nvhost_cdma_update(&channel->cdma);
137 nvhost_module_idle_mult(channel->dev, nr_completed);
138}
139
140static void action_ctxsave(struct nvhost_waitlist *waiter)
141{
142 struct nvhost_hwctx *hwctx = waiter->data;
143 struct nvhost_channel *channel = hwctx->channel;
144
145 if (channel->ctxhandler->save_service)
146 channel->ctxhandler->save_service(hwctx);
147}
148
149static void action_wakeup(struct nvhost_waitlist *waiter)
150{
151 wait_queue_head_t *wq = waiter->data;
152
153 wake_up(wq);
154}
155
156static void action_wakeup_interruptible(struct nvhost_waitlist *waiter)
157{
158 wait_queue_head_t *wq = waiter->data;
159
160 wake_up_interruptible(wq);
161}
162
163typedef void (*action_handler)(struct nvhost_waitlist *waiter);
164
165static action_handler action_handlers[NVHOST_INTR_ACTION_COUNT] = {
166 action_submit_complete,
167 action_ctxsave,
168 action_wakeup,
169 action_wakeup_interruptible,
170};
171
172static void run_handlers(struct list_head completed[NVHOST_INTR_ACTION_COUNT])
173{
174 struct list_head *head = completed;
175 int i;
176
177 for (i = 0; i < NVHOST_INTR_ACTION_COUNT; ++i, ++head) {
178 action_handler handler = action_handlers[i];
179 struct nvhost_waitlist *waiter, *next;
180
181 list_for_each_entry_safe(waiter, next, head, list) {
182 list_del(&waiter->list);
183 handler(waiter);
184 WARN_ON(atomic_xchg(&waiter->state, WLS_HANDLED) != WLS_REMOVED);
185 kref_put(&waiter->refcount, waiter_release);
186 }
187 }
188}
189
190/**
191 * Remove & handle all waiters that have completed for the given syncpt
192 */
193static int process_wait_list(struct nvhost_intr *intr,
194 struct nvhost_intr_syncpt *syncpt,
195 u32 threshold)
196{
197 struct list_head completed[NVHOST_INTR_ACTION_COUNT];
198 unsigned int i;
199 int empty;
200
201 for (i = 0; i < NVHOST_INTR_ACTION_COUNT; ++i)
202 INIT_LIST_HEAD(completed + i);
203
204 spin_lock(&syncpt->lock);
205
206 remove_completed_waiters(&syncpt->wait_head, threshold, completed);
207
208 empty = list_empty(&syncpt->wait_head);
209 if (!empty)
210 reset_threshold_interrupt(intr, &syncpt->wait_head,
211 syncpt->id);
212
213 spin_unlock(&syncpt->lock);
214
215 run_handlers(completed);
216
217 return empty;
218}
219
220/*** host syncpt interrupt service functions ***/
221/**
222 * Sync point threshold interrupt service thread function
223 * Handles sync point threshold triggers, in thread context
224 */
225irqreturn_t nvhost_syncpt_thresh_fn(int irq, void *dev_id)
226{
227 struct nvhost_intr_syncpt *syncpt = dev_id;
228 unsigned int id = syncpt->id;
229 struct nvhost_intr *intr = intr_syncpt_to_intr(syncpt);
230 struct nvhost_master *dev = intr_to_dev(intr);
231
232 (void)process_wait_list(intr, syncpt,
233 nvhost_syncpt_update_min(&dev->syncpt, id));
234
235 return IRQ_HANDLED;
236}
237
238/**
239 * free a syncpt's irq. syncpt interrupt should be disabled first.
240 */
241static void free_syncpt_irq(struct nvhost_intr_syncpt *syncpt)
242{
243 if (syncpt->irq_requested) {
244 free_irq(syncpt->irq, syncpt);
245 syncpt->irq_requested = 0;
246 }
247}
248
249
250/*** host general interrupt service functions ***/
251
252
253/*** Main API ***/
254
255int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
256 enum nvhost_intr_action action, void *data,
257 void *_waiter,
258 void **ref)
259{
260 struct nvhost_waitlist *waiter = _waiter;
261 struct nvhost_intr_syncpt *syncpt;
262 int queue_was_empty;
263 int err;
264
265 BUG_ON(waiter == NULL);
266
267 BUG_ON(!(intr_op(intr).set_syncpt_threshold &&
268 intr_op(intr).enable_syncpt_intr));
269
270 /* initialize a new waiter */
271 INIT_LIST_HEAD(&waiter->list);
272 kref_init(&waiter->refcount);
273 if (ref)
274 kref_get(&waiter->refcount);
275 waiter->thresh = thresh;
276 waiter->action = action;
277 atomic_set(&waiter->state, WLS_PENDING);
278 waiter->data = data;
279 waiter->count = 1;
280
281 BUG_ON(id >= intr_to_dev(intr)->syncpt.nb_pts);
282 syncpt = intr->syncpt + id;
283
284 spin_lock(&syncpt->lock);
285
286 /* lazily request irq for this sync point */
287 if (!syncpt->irq_requested) {
288 spin_unlock(&syncpt->lock);
289
290 mutex_lock(&intr->mutex);
291 BUG_ON(!(intr_op(intr).request_syncpt_irq));
292 err = intr_op(intr).request_syncpt_irq(syncpt);
293 mutex_unlock(&intr->mutex);
294
295 if (err) {
296 kfree(waiter);
297 return err;
298 }
299
300 spin_lock(&syncpt->lock);
301 }
302
303 queue_was_empty = list_empty(&syncpt->wait_head);
304
305 if (add_waiter_to_queue(waiter, &syncpt->wait_head)) {
306 /* added at head of list - new threshold value */
307 intr_op(intr).set_syncpt_threshold(intr, id, thresh);
308
309 /* added as first waiter - enable interrupt */
310 if (queue_was_empty)
311 intr_op(intr).enable_syncpt_intr(intr, id);
312 }
313
314 spin_unlock(&syncpt->lock);
315
316 if (ref)
317 *ref = waiter;
318 return 0;
319}
320
321void *nvhost_intr_alloc_waiter()
322{
323 return kzalloc(sizeof(struct nvhost_waitlist),
324 GFP_KERNEL|__GFP_REPEAT);
325}
326
327void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref)
328{
329 struct nvhost_waitlist *waiter = ref;
330
331 while (atomic_cmpxchg(&waiter->state,
332 WLS_PENDING, WLS_CANCELLED) == WLS_REMOVED)
333 schedule();
334
335 kref_put(&waiter->refcount, waiter_release);
336}
337
338
339/*** Init & shutdown ***/
340
341int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync)
342{
343 unsigned int id;
344 struct nvhost_intr_syncpt *syncpt;
345 struct nvhost_master *host =
346 container_of(intr, struct nvhost_master, intr);
347 u32 nb_pts = host->syncpt.nb_pts;
348
349 mutex_init(&intr->mutex);
350 intr->host_general_irq = irq_gen;
351 intr->host_general_irq_requested = false;
352
353 for (id = 0, syncpt = intr->syncpt;
354 id < nb_pts;
355 ++id, ++syncpt) {
356 syncpt->intr = &host->intr;
357 syncpt->id = id;
358 syncpt->irq = irq_sync + id;
359 syncpt->irq_requested = 0;
360 spin_lock_init(&syncpt->lock);
361 INIT_LIST_HEAD(&syncpt->wait_head);
362 snprintf(syncpt->thresh_irq_name,
363 sizeof(syncpt->thresh_irq_name),
364 "host_sp_%02d", id);
365 }
366
367 return 0;
368}
369
370void nvhost_intr_deinit(struct nvhost_intr *intr)
371{
372 nvhost_intr_stop(intr);
373}
374
375void nvhost_intr_start(struct nvhost_intr *intr, u32 hz)
376{
377 BUG_ON(!(intr_op(intr).init_host_sync &&
378 intr_op(intr).set_host_clocks_per_usec &&
379 intr_op(intr).request_host_general_irq));
380
381 mutex_lock(&intr->mutex);
382
383 intr_op(intr).init_host_sync(intr);
384 intr_op(intr).set_host_clocks_per_usec(intr,
385 (hz + 1000000 - 1)/1000000);
386
387 intr_op(intr).request_host_general_irq(intr);
388
389 mutex_unlock(&intr->mutex);
390}
391
392void nvhost_intr_stop(struct nvhost_intr *intr)
393{
394 unsigned int id;
395 struct nvhost_intr_syncpt *syncpt;
396 u32 nb_pts = intr_to_dev(intr)->syncpt.nb_pts;
397
398 BUG_ON(!(intr_op(intr).disable_all_syncpt_intrs &&
399 intr_op(intr).free_host_general_irq));
400
401 mutex_lock(&intr->mutex);
402
403 intr_op(intr).disable_all_syncpt_intrs(intr);
404
405 for (id = 0, syncpt = intr->syncpt;
406 id < nb_pts;
407 ++id, ++syncpt) {
408 struct nvhost_waitlist *waiter, *next;
409 list_for_each_entry_safe(waiter, next, &syncpt->wait_head, list) {
410 if (atomic_cmpxchg(&waiter->state, WLS_CANCELLED, WLS_HANDLED)
411 == WLS_CANCELLED) {
412 list_del(&waiter->list);
413 kref_put(&waiter->refcount, waiter_release);
414 }
415 }
416
417 if (!list_empty(&syncpt->wait_head)) { /* output diagnostics */
418 printk(KERN_DEBUG "%s id=%d\n", __func__, id);
419 BUG_ON(1);
420 }
421
422 free_syncpt_irq(syncpt);
423 }
424
425 intr_op(intr).free_host_general_irq(intr);
426
427 mutex_unlock(&intr->mutex);
428}
diff --git a/drivers/video/tegra/host/nvhost_intr.h b/drivers/video/tegra/host/nvhost_intr.h
new file mode 100644
index 00000000000..26ab04ebd4a
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_intr.h
@@ -0,0 +1,115 @@
1/*
2 * drivers/video/tegra/host/nvhost_intr.h
3 *
4 * Tegra Graphics Host Interrupt Management
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_INTR_H
22#define __NVHOST_INTR_H
23
24#include <linux/kthread.h>
25#include <linux/semaphore.h>
26#include <linux/interrupt.h>
27
28struct nvhost_channel;
29
30enum nvhost_intr_action {
31 /**
32 * Perform cleanup after a submit has completed.
33 * 'data' points to a channel
34 */
35 NVHOST_INTR_ACTION_SUBMIT_COMPLETE = 0,
36
37 /**
38 * Save a HW context.
39 * 'data' points to a context
40 */
41 NVHOST_INTR_ACTION_CTXSAVE,
42
43 /**
44 * Wake up a task.
45 * 'data' points to a wait_queue_head_t
46 */
47 NVHOST_INTR_ACTION_WAKEUP,
48
49 /**
50 * Wake up a interruptible task.
51 * 'data' points to a wait_queue_head_t
52 */
53 NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE,
54
55 NVHOST_INTR_ACTION_COUNT
56};
57
58struct nvhost_intr;
59
60struct nvhost_intr_syncpt {
61 struct nvhost_intr *intr;
62 u8 id;
63 u8 irq_requested;
64 u16 irq;
65 spinlock_t lock;
66 struct list_head wait_head;
67 char thresh_irq_name[12];
68};
69
70struct nvhost_intr {
71 struct nvhost_intr_syncpt *syncpt;
72 struct mutex mutex;
73 int host_general_irq;
74 bool host_general_irq_requested;
75};
76#define intr_to_dev(x) container_of(x, struct nvhost_master, intr)
77#define intr_op(intr) (intr_to_dev(intr)->op.intr)
78#define intr_syncpt_to_intr(is) (is->intr)
79
80/**
81 * Schedule an action to be taken when a sync point reaches the given threshold.
82 *
83 * @id the sync point
84 * @thresh the threshold
85 * @action the action to take
86 * @data a pointer to extra data depending on action, see above
87 * @waiter waiter allocated with nvhost_intr_alloc_waiter - assumes ownership
88 * @ref must be passed if cancellation is possible, else NULL
89 *
90 * This is a non-blocking api.
91 */
92int nvhost_intr_add_action(struct nvhost_intr *intr, u32 id, u32 thresh,
93 enum nvhost_intr_action action, void *data,
94 void *waiter,
95 void **ref);
96
97/**
98 * Allocate a waiter.
99 */
100void *nvhost_intr_alloc_waiter(void);
101
102/**
103 * Unreference an action submitted to nvhost_intr_add_action().
104 * You must call this if you passed non-NULL as ref.
105 * @ref the ref returned from nvhost_intr_add_action()
106 */
107void nvhost_intr_put_ref(struct nvhost_intr *intr, void *ref);
108
109int nvhost_intr_init(struct nvhost_intr *intr, u32 irq_gen, u32 irq_sync);
110void nvhost_intr_deinit(struct nvhost_intr *intr);
111void nvhost_intr_start(struct nvhost_intr *intr, u32 hz);
112void nvhost_intr_stop(struct nvhost_intr *intr);
113
114irqreturn_t nvhost_syncpt_thresh_fn(int irq, void *dev_id);
115#endif
diff --git a/drivers/video/tegra/host/nvhost_job.c b/drivers/video/tegra/host/nvhost_job.c
new file mode 100644
index 00000000000..df7a62d689b
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_job.c
@@ -0,0 +1,339 @@
1/*
2 * drivers/video/tegra/host/nvhost_job.c
3 *
4 * Tegra Graphics Host Job
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/slab.h>
22#include <linux/kref.h>
23#include <linux/err.h>
24#include <linux/vmalloc.h>
25#include <mach/nvmap.h>
26#include "nvhost_channel.h"
27#include "nvhost_job.h"
28#include "dev.h"
29
30/* Magic to use to fill freed handle slots */
31#define BAD_MAGIC 0xdeadbeef
32
33static int job_size(struct nvhost_submit_hdr_ext *hdr)
34{
35 int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
36 int num_waitchks = hdr ? hdr->num_waitchks : 0;
37
38 return sizeof(struct nvhost_job)
39 + num_pins * sizeof(struct nvmap_pinarray_elem)
40 + num_pins * sizeof(struct nvmap_handle *)
41 + num_waitchks * sizeof(struct nvhost_waitchk);
42}
43
44static int gather_size(int num_cmdbufs)
45{
46 return num_cmdbufs * sizeof(struct nvhost_channel_gather);
47}
48
49static void free_gathers(struct nvhost_job *job)
50{
51 if (job->gathers) {
52 nvmap_munmap(job->gather_mem, job->gathers);
53 job->gathers = NULL;
54 }
55 if (job->gather_mem) {
56 nvmap_free(job->nvmap, job->gather_mem);
57 job->gather_mem = NULL;
58 }
59}
60
61static int alloc_gathers(struct nvhost_job *job,
62 int num_cmdbufs)
63{
64 int err = 0;
65
66 job->gather_mem = NULL;
67 job->gathers = NULL;
68 job->gather_mem_size = 0;
69
70 if (num_cmdbufs) {
71 /* Allocate memory */
72 job->gather_mem = nvmap_alloc(job->nvmap,
73 gather_size(num_cmdbufs),
74 32, NVMAP_HANDLE_CACHEABLE, 0);
75 if (IS_ERR_OR_NULL(job->gather_mem)) {
76 err = PTR_ERR(job->gather_mem);
77 job->gather_mem = NULL;
78 goto error;
79 }
80 job->gather_mem_size = gather_size(num_cmdbufs);
81
82 /* Map memory to kernel */
83 job->gathers = nvmap_mmap(job->gather_mem);
84 if (IS_ERR_OR_NULL(job->gathers)) {
85 err = PTR_ERR(job->gathers);
86 job->gathers = NULL;
87 goto error;
88 }
89 }
90
91 return 0;
92
93error:
94 free_gathers(job);
95 return err;
96}
97
98static int realloc_gathers(struct nvhost_job *oldjob,
99 struct nvhost_job *newjob,
100 int num_cmdbufs)
101{
102 int err = 0;
103
104 /* Check if we can reuse gather buffer */
105 if (oldjob->gather_mem_size < gather_size(num_cmdbufs)
106 || oldjob->nvmap != newjob->nvmap) {
107 free_gathers(oldjob);
108 err = alloc_gathers(newjob, num_cmdbufs);
109 } else {
110 newjob->gather_mem = oldjob->gather_mem;
111 newjob->gathers = oldjob->gathers;
112 newjob->gather_mem_size = oldjob->gather_mem_size;
113
114 oldjob->gather_mem = NULL;
115 oldjob->gathers = NULL;
116 oldjob->gather_mem_size = 0;
117 }
118 return err;
119}
120
121static void init_fields(struct nvhost_job *job,
122 struct nvhost_submit_hdr_ext *hdr,
123 int priority, int clientid)
124{
125 int num_pins = hdr ? (hdr->num_relocs + hdr->num_cmdbufs)*2 : 0;
126 int num_waitchks = hdr ? hdr->num_waitchks : 0;
127 void *mem = job;
128
129 /* First init state to zero */
130 job->num_gathers = 0;
131 job->num_pins = 0;
132 job->num_unpins = 0;
133 job->num_waitchk = 0;
134 job->waitchk_mask = 0;
135 job->syncpt_id = 0;
136 job->syncpt_incrs = 0;
137 job->syncpt_end = 0;
138 job->priority = priority;
139 job->clientid = clientid;
140 job->null_kickoff = false;
141 job->first_get = 0;
142 job->num_slots = 0;
143
144 /* Redistribute memory to the structs */
145 mem += sizeof(struct nvhost_job);
146 if (num_pins) {
147 job->pinarray = mem;
148 mem += num_pins * sizeof(struct nvmap_pinarray_elem);
149 job->unpins = mem;
150 mem += num_pins * sizeof(struct nvmap_handle *);
151 } else {
152 job->pinarray = NULL;
153 job->unpins = NULL;
154 }
155
156 job->waitchk = num_waitchks ? mem : NULL;
157
158 /* Copy information from header */
159 if (hdr) {
160 job->waitchk_mask = hdr->waitchk_mask;
161 job->syncpt_id = hdr->syncpt_id;
162 job->syncpt_incrs = hdr->syncpt_incrs;
163 }
164}
165
166struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
167 struct nvhost_hwctx *hwctx,
168 struct nvhost_submit_hdr_ext *hdr,
169 struct nvmap_client *nvmap,
170 int priority,
171 int clientid)
172{
173 struct nvhost_job *job = NULL;
174 int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
175 int err = 0;
176
177 job = vzalloc(job_size(hdr));
178 if (!job)
179 goto error;
180
181 kref_init(&job->ref);
182 job->ch = ch;
183 job->hwctx = hwctx;
184 if (hwctx)
185 hwctx->h->get(hwctx);
186 job->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
187
188 err = alloc_gathers(job, num_cmdbufs);
189 if (err)
190 goto error;
191
192 init_fields(job, hdr, priority, clientid);
193
194 return job;
195
196error:
197 if (job)
198 nvhost_job_put(job);
199 return NULL;
200}
201
202struct nvhost_job *nvhost_job_realloc(
203 struct nvhost_job *oldjob,
204 struct nvhost_hwctx *hwctx,
205 struct nvhost_submit_hdr_ext *hdr,
206 struct nvmap_client *nvmap,
207 int priority, int clientid)
208{
209 struct nvhost_job *newjob = NULL;
210 int num_cmdbufs = hdr ? hdr->num_cmdbufs : 0;
211 int err = 0;
212
213 newjob = vzalloc(job_size(hdr));
214 if (!newjob)
215 goto error;
216 kref_init(&newjob->ref);
217 newjob->ch = oldjob->ch;
218 newjob->hwctx = hwctx;
219 if (hwctx)
220 newjob->hwctx->h->get(newjob->hwctx);
221 newjob->timeout = oldjob->timeout;
222 newjob->nvmap = nvmap ? nvmap_client_get(nvmap) : NULL;
223
224 err = realloc_gathers(oldjob, newjob, num_cmdbufs);
225 if (err)
226 goto error;
227
228 nvhost_job_put(oldjob);
229
230 init_fields(newjob, hdr, priority, clientid);
231
232 return newjob;
233
234error:
235 if (newjob)
236 nvhost_job_put(newjob);
237 if (oldjob)
238 nvhost_job_put(oldjob);
239 return NULL;
240}
241
242void nvhost_job_get(struct nvhost_job *job)
243{
244 kref_get(&job->ref);
245}
246
247static void job_free(struct kref *ref)
248{
249 struct nvhost_job *job = container_of(ref, struct nvhost_job, ref);
250
251 if (job->hwctxref)
252 job->hwctxref->h->put(job->hwctxref);
253 if (job->hwctx)
254 job->hwctx->h->put(job->hwctx);
255 if (job->gathers)
256 nvmap_munmap(job->gather_mem, job->gathers);
257 if (job->gather_mem)
258 nvmap_free(job->nvmap, job->gather_mem);
259 if (job->nvmap)
260 nvmap_client_put(job->nvmap);
261 vfree(job);
262}
263
264/* Acquire reference to a hardware context. Used for keeping saved contexts in
265 * memory. */
266void nvhost_job_get_hwctx(struct nvhost_job *job, struct nvhost_hwctx *hwctx)
267{
268 BUG_ON(job->hwctxref);
269
270 job->hwctxref = hwctx;
271 hwctx->h->get(hwctx);
272}
273
274void nvhost_job_put(struct nvhost_job *job)
275{
276 kref_put(&job->ref, job_free);
277}
278
279void nvhost_job_add_gather(struct nvhost_job *job,
280 u32 mem_id, u32 words, u32 offset)
281{
282 struct nvmap_pinarray_elem *pin;
283 struct nvhost_channel_gather *cur_gather =
284 &job->gathers[job->num_gathers];
285
286 pin = &job->pinarray[job->num_pins++];
287 pin->patch_mem = (u32)nvmap_ref_to_handle(job->gather_mem);
288 pin->patch_offset = (void *)&(cur_gather->mem) - (void *)job->gathers;
289 pin->pin_mem = nvmap_convert_handle_u2k(mem_id);
290 pin->pin_offset = offset;
291 cur_gather->words = words;
292 cur_gather->mem_id = mem_id;
293 cur_gather->offset = offset;
294 job->num_gathers += 1;
295}
296
297int nvhost_job_pin(struct nvhost_job *job)
298{
299 int err = 0;
300
301 /* pin mem handles and patch physical addresses */
302 job->num_unpins = nvmap_pin_array(job->nvmap,
303 nvmap_ref_to_handle(job->gather_mem),
304 job->pinarray, job->num_pins,
305 job->unpins);
306 if (job->num_unpins < 0)
307 err = job->num_unpins;
308
309 return err;
310}
311
312void nvhost_job_unpin(struct nvhost_job *job)
313{
314 nvmap_unpin_handles(job->nvmap, job->unpins,
315 job->num_unpins);
316 memset(job->unpins, BAD_MAGIC,
317 job->num_unpins * sizeof(struct nvmap_handle *));
318}
319
320/**
321 * Debug routine used to dump job entries
322 */
323void nvhost_job_dump(struct device *dev, struct nvhost_job *job)
324{
325 dev_dbg(dev, " SYNCPT_ID %d\n",
326 job->syncpt_id);
327 dev_dbg(dev, " SYNCPT_VAL %d\n",
328 job->syncpt_end);
329 dev_dbg(dev, " FIRST_GET 0x%x\n",
330 job->first_get);
331 dev_dbg(dev, " TIMEOUT %d\n",
332 job->timeout);
333 dev_dbg(dev, " CTX 0x%p\n",
334 job->hwctx);
335 dev_dbg(dev, " NUM_SLOTS %d\n",
336 job->num_slots);
337 dev_dbg(dev, " NUM_HANDLES %d\n",
338 job->num_unpins);
339}
diff --git a/drivers/video/tegra/host/nvhost_job.h b/drivers/video/tegra/host/nvhost_job.h
new file mode 100644
index 00000000000..ad9d1af60da
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_job.h
@@ -0,0 +1,150 @@
1/*
2 * drivers/video/tegra/host/nvhost_job.h
3 *
4 * Tegra Graphics Host Interrupt Management
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_JOB_H
22#define __NVHOST_JOB_H
23
24#include <linux/nvhost_ioctl.h>
25
26struct nvhost_channel;
27struct nvhost_hwctx;
28struct nvmap_client;
29struct nvhost_waitchk;
30struct nvmap_handle;
31
32/*
33 * Each submit is tracked as a nvhost_job.
34 */
35struct nvhost_job {
36 /* When refcount goes to zero, job can be freed */
37 struct kref ref;
38
39 /* List entry */
40 struct list_head list;
41
42 /* Channel where job is submitted to */
43 struct nvhost_channel *ch;
44
45 /* Hardware context valid for this client */
46 struct nvhost_hwctx *hwctx;
47 int clientid;
48
49 /* Nvmap to be used for pinning & unpinning memory */
50 struct nvmap_client *nvmap;
51
52 /* Gathers and their memory */
53 struct nvmap_handle_ref *gather_mem;
54 struct nvhost_channel_gather *gathers;
55 int num_gathers;
56 int gather_mem_size;
57
58 /* Wait checks to be processed at submit time */
59 struct nvhost_waitchk *waitchk;
60 int num_waitchk;
61 u32 waitchk_mask;
62
63 /* Array of handles to be pinned & unpinned */
64 struct nvmap_pinarray_elem *pinarray;
65 int num_pins;
66 struct nvmap_handle **unpins;
67 int num_unpins;
68
69 /* Sync point id, number of increments and end related to the submit */
70 u32 syncpt_id;
71 u32 syncpt_incrs;
72 u32 syncpt_end;
73
74 /* Priority of this submit. */
75 int priority;
76
77 /* Maximum time to wait for this job */
78 int timeout;
79
80 /* Null kickoff prevents submit from being sent to hardware */
81 bool null_kickoff;
82
83 /* Index and number of slots used in the push buffer */
84 int first_get;
85 int num_slots;
86
87 /* Context to be freed */
88 struct nvhost_hwctx *hwctxref;
89};
90
91/*
92 * Allocate memory for a job. Just enough memory will be allocated to
93 * accomodate the submit announced in submit header.
94 */
95struct nvhost_job *nvhost_job_alloc(struct nvhost_channel *ch,
96 struct nvhost_hwctx *hwctx,
97 struct nvhost_submit_hdr_ext *hdr,
98 struct nvmap_client *nvmap,
99 int priority, int clientid);
100
101/*
102 * Allocate memory for a job. Just enough memory will be allocated to
103 * accomodate the submit announced in submit header. Gather memory from
104 * oldjob will be reused, and nvhost_job_put() will be called to it.
105 */
106struct nvhost_job *nvhost_job_realloc(struct nvhost_job *oldjob,
107 struct nvhost_hwctx *hwctx,
108 struct nvhost_submit_hdr_ext *hdr,
109 struct nvmap_client *nvmap,
110 int priority, int clientid);
111
112/*
113 * Add a gather to a job.
114 */
115void nvhost_job_add_gather(struct nvhost_job *job,
116 u32 mem_id, u32 words, u32 offset);
117
118/*
119 * Increment reference going to nvhost_job.
120 */
121void nvhost_job_get(struct nvhost_job *job);
122
123/*
124 * Increment reference for a hardware context.
125 */
126void nvhost_job_get_hwctx(struct nvhost_job *job, struct nvhost_hwctx *hwctx);
127
128/*
129 * Decrement reference job, free if goes to zero.
130 */
131void nvhost_job_put(struct nvhost_job *job);
132
133/*
134 * Pin memory related to job. This handles relocation of addresses to the
135 * host1x address space. Handles both the gather memory and any other memory
136 * referred to from the gather buffers.
137 */
138int nvhost_job_pin(struct nvhost_job *job);
139
140/*
141 * Unpin memory related to job.
142 */
143void nvhost_job_unpin(struct nvhost_job *job);
144
145/*
146 * Dump contents of job to debug output.
147 */
148void nvhost_job_dump(struct device *dev, struct nvhost_job *job);
149
150#endif
diff --git a/drivers/video/tegra/host/nvhost_syncpt.c b/drivers/video/tegra/host/nvhost_syncpt.c
new file mode 100644
index 00000000000..eb5176ea1bf
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_syncpt.c
@@ -0,0 +1,319 @@
1/*
2 * drivers/video/tegra/host/nvhost_syncpt.c
3 *
4 * Tegra Graphics Host Syncpoints
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/nvhost_ioctl.h>
22#include <linux/platform_device.h>
23#include "nvhost_syncpt.h"
24#include "dev.h"
25
26#define MAX_STUCK_CHECK_COUNT 15
27
28/**
29 * Resets syncpoint and waitbase values to sw shadows
30 */
31void nvhost_syncpt_reset(struct nvhost_syncpt *sp)
32{
33 u32 i;
34 BUG_ON(!(syncpt_op(sp).reset && syncpt_op(sp).reset_wait_base));
35
36 for (i = 0; i < sp->nb_pts; i++)
37 syncpt_op(sp).reset(sp, i);
38 for (i = 0; i < sp->nb_bases; i++)
39 syncpt_op(sp).reset_wait_base(sp, i);
40 wmb();
41}
42
43/**
44 * Updates sw shadow state for client managed registers
45 */
46void nvhost_syncpt_save(struct nvhost_syncpt *sp)
47{
48 u32 i;
49 BUG_ON(!(syncpt_op(sp).update_min && syncpt_op(sp).read_wait_base));
50
51 for (i = 0; i < sp->nb_pts; i++) {
52 if (client_managed(i))
53 syncpt_op(sp).update_min(sp, i);
54 else
55 BUG_ON(!nvhost_syncpt_min_eq_max(sp, i));
56 }
57
58 for (i = 0; i < sp->nb_bases; i++)
59 syncpt_op(sp).read_wait_base(sp, i);
60}
61
62/**
63 * Updates the last value read from hardware.
64 */
65u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id)
66{
67 BUG_ON(!syncpt_op(sp).update_min);
68
69 return syncpt_op(sp).update_min(sp, id);
70}
71
72/**
73 * Get the current syncpoint value
74 */
75u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id)
76{
77 u32 val;
78 BUG_ON(!syncpt_op(sp).update_min);
79 nvhost_module_busy(syncpt_to_dev(sp)->dev);
80 val = syncpt_op(sp).update_min(sp, id);
81 nvhost_module_idle(syncpt_to_dev(sp)->dev);
82 return val;
83}
84
85/**
86 * Get the current syncpoint base
87 */
88u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id)
89{
90 u32 val;
91 BUG_ON(!syncpt_op(sp).read_wait_base);
92 nvhost_module_busy(syncpt_to_dev(sp)->dev);
93 syncpt_op(sp).read_wait_base(sp, id);
94 val = sp->base_val[id];
95 nvhost_module_idle(syncpt_to_dev(sp)->dev);
96 return val;
97}
98
99/**
100 * Write a cpu syncpoint increment to the hardware, without touching
101 * the cache. Caller is responsible for host being powered.
102 */
103void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id)
104{
105 BUG_ON(!syncpt_op(sp).cpu_incr);
106 syncpt_op(sp).cpu_incr(sp, id);
107}
108
109/**
110 * Increment syncpoint value from cpu, updating cache
111 */
112void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id)
113{
114 if (client_managed(id))
115 nvhost_syncpt_incr_max(sp, id, 1);
116 nvhost_module_busy(syncpt_to_dev(sp)->dev);
117 nvhost_syncpt_cpu_incr(sp, id);
118 nvhost_module_idle(syncpt_to_dev(sp)->dev);
119}
120
121/**
122 * Main entrypoint for syncpoint value waits.
123 */
124int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id,
125 u32 thresh, u32 timeout, u32 *value)
126{
127 DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
128 void *ref;
129 void *waiter;
130 int err = 0, check_count = 0, low_timeout = 0;
131 u32 val;
132
133 if (value)
134 *value = 0;
135
136 /* first check cache */
137 if (nvhost_syncpt_is_expired(sp, id, thresh)) {
138 if (value)
139 *value = nvhost_syncpt_read_min(sp, id);
140 return 0;
141 }
142
143 /* keep host alive */
144 nvhost_module_busy(syncpt_to_dev(sp)->dev);
145
146 /* try to read from register */
147 val = syncpt_op(sp).update_min(sp, id);
148 if (nvhost_syncpt_is_expired(sp, id, thresh)) {
149 if (value)
150 *value = val;
151 goto done;
152 }
153
154 if (!timeout) {
155 err = -EAGAIN;
156 goto done;
157 }
158
159 /* schedule a wakeup when the syncpoint value is reached */
160 waiter = nvhost_intr_alloc_waiter();
161 if (!waiter) {
162 err = -ENOMEM;
163 goto done;
164 }
165
166 err = nvhost_intr_add_action(&(syncpt_to_dev(sp)->intr), id, thresh,
167 NVHOST_INTR_ACTION_WAKEUP_INTERRUPTIBLE, &wq,
168 waiter,
169 &ref);
170 if (err)
171 goto done;
172
173 err = -EAGAIN;
174 /* Caller-specified timeout may be impractically low */
175 if (timeout < SYNCPT_CHECK_PERIOD)
176 low_timeout = timeout;
177
178 /* wait for the syncpoint, or timeout, or signal */
179 while (timeout) {
180 u32 check = min_t(u32, SYNCPT_CHECK_PERIOD, timeout);
181 int remain = wait_event_interruptible_timeout(wq,
182 nvhost_syncpt_is_expired(sp, id, thresh),
183 check);
184 if (remain > 0) {
185 if (value)
186 *value = nvhost_syncpt_read_min(sp, id);
187 err = 0;
188 break;
189 }
190 if (remain < 0) {
191 err = remain;
192 break;
193 }
194 if (timeout != NVHOST_NO_TIMEOUT)
195 timeout -= check;
196 if (timeout) {
197 dev_warn(&syncpt_to_dev(sp)->dev->dev,
198 "%s: syncpoint id %d (%s) stuck waiting %d, timeout=%d\n",
199 current->comm, id, syncpt_op(sp).name(sp, id),
200 thresh, timeout);
201 syncpt_op(sp).debug(sp);
202 if (check_count > MAX_STUCK_CHECK_COUNT) {
203 if (low_timeout) {
204 dev_warn(&syncpt_to_dev(sp)->dev->dev,
205 "is timeout %d too low?\n",
206 low_timeout);
207 }
208 nvhost_debug_dump(syncpt_to_dev(sp));
209 BUG();
210 }
211 check_count++;
212 }
213 }
214 nvhost_intr_put_ref(&(syncpt_to_dev(sp)->intr), ref);
215
216done:
217 nvhost_module_idle(syncpt_to_dev(sp)->dev);
218 return err;
219}
220
221/**
222 * Returns true if syncpoint is expired, false if we may need to wait
223 */
224bool nvhost_syncpt_is_expired(
225 struct nvhost_syncpt *sp,
226 u32 id,
227 u32 thresh)
228{
229 u32 current_val;
230 u32 future_val;
231 smp_rmb();
232 current_val = (u32)atomic_read(&sp->min_val[id]);
233 future_val = (u32)atomic_read(&sp->max_val[id]);
234
235 /* Note the use of unsigned arithmetic here (mod 1<<32).
236 *
237 * c = current_val = min_val = the current value of the syncpoint.
238 * t = thresh = the value we are checking
239 * f = future_val = max_val = the value c will reach when all
240 * outstanding increments have completed.
241 *
242 * Note that c always chases f until it reaches f.
243 *
244 * Dtf = (f - t)
245 * Dtc = (c - t)
246 *
247 * Consider all cases:
248 *
249 * A) .....c..t..f..... Dtf < Dtc need to wait
250 * B) .....c.....f..t.. Dtf > Dtc expired
251 * C) ..t..c.....f..... Dtf > Dtc expired (Dct very large)
252 *
253 * Any case where f==c: always expired (for any t). Dtf == Dcf
254 * Any case where t==c: always expired (for any f). Dtf >= Dtc (because Dtc==0)
255 * Any case where t==f!=c: always wait. Dtf < Dtc (because Dtf==0,
256 * Dtc!=0)
257 *
258 * Other cases:
259 *
260 * A) .....t..f..c..... Dtf < Dtc need to wait
261 * A) .....f..c..t..... Dtf < Dtc need to wait
262 * A) .....f..t..c..... Dtf > Dtc expired
263 *
264 * So:
265 * Dtf >= Dtc implies EXPIRED (return true)
266 * Dtf < Dtc implies WAIT (return false)
267 *
268 * Note: If t is expired then we *cannot* wait on it. We would wait
269 * forever (hang the system).
270 *
271 * Note: do NOT get clever and remove the -thresh from both sides. It
272 * is NOT the same.
273 *
274 * If future valueis zero, we have a client managed sync point. In that
275 * case we do a direct comparison.
276 */
277 if (!client_managed(id))
278 return future_val - thresh >= current_val - thresh;
279 else
280 return (s32)(current_val - thresh) >= 0;
281}
282
283void nvhost_syncpt_debug(struct nvhost_syncpt *sp)
284{
285 syncpt_op(sp).debug(sp);
286}
287
288int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx)
289{
290 struct nvhost_master *host = syncpt_to_dev(sp);
291 u32 reg;
292
293 nvhost_module_busy(host->dev);
294 reg = syncpt_op(sp).mutex_try_lock(sp, idx);
295 if (reg) {
296 nvhost_module_idle(host->dev);
297 return -EBUSY;
298 }
299 atomic_inc(&sp->lock_counts[idx]);
300 return 0;
301}
302
303void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx)
304{
305 syncpt_op(sp).mutex_unlock(sp, idx);
306 nvhost_module_idle(syncpt_to_dev(sp)->dev);
307 atomic_dec(&sp->lock_counts[idx]);
308}
309
310/* check for old WAITs to be removed (avoiding a wrap) */
311int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
312 struct nvmap_client *nvmap,
313 u32 waitchk_mask,
314 struct nvhost_waitchk *wait,
315 int num_waitchk)
316{
317 return syncpt_op(sp).wait_check(sp, nvmap,
318 waitchk_mask, wait, num_waitchk);
319}
diff --git a/drivers/video/tegra/host/nvhost_syncpt.h b/drivers/video/tegra/host/nvhost_syncpt.h
new file mode 100644
index 00000000000..5b339178d1e
--- /dev/null
+++ b/drivers/video/tegra/host/nvhost_syncpt.h
@@ -0,0 +1,155 @@
1/*
2 * drivers/video/tegra/host/nvhost_syncpt.h
3 *
4 * Tegra Graphics Host Syncpoints
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#ifndef __NVHOST_SYNCPT_H
22#define __NVHOST_SYNCPT_H
23
24#include <linux/kernel.h>
25#include <linux/sched.h>
26#include <linux/nvhost.h>
27#include <mach/nvmap.h>
28#include <linux/atomic.h>
29
30struct nvhost_syncpt;
31struct nvhost_waitchk;
32
33/* host managed and invalid syncpt id */
34#define NVSYNCPT_GRAPHICS_HOST (0)
35#define NVSYNCPT_INVALID (-1)
36
37struct nvhost_syncpt {
38 atomic_t *min_val;
39 atomic_t *max_val;
40 u32 *base_val;
41 u32 nb_pts;
42 u32 nb_bases;
43 u32 client_managed;
44 atomic_t *lock_counts;
45 u32 nb_mlocks;
46};
47
48int nvhost_syncpt_init(struct nvhost_syncpt *);
49#define client_managed(id) (BIT(id) & sp->client_managed)
50#define syncpt_to_dev(sp) container_of(sp, struct nvhost_master, syncpt)
51#define syncpt_op(sp) (syncpt_to_dev(sp)->op.syncpt)
52#define SYNCPT_CHECK_PERIOD (2*HZ)
53
54
55/**
56 * Updates the value sent to hardware.
57 */
58static inline u32 nvhost_syncpt_incr_max(struct nvhost_syncpt *sp,
59 u32 id, u32 incrs)
60{
61 return (u32)atomic_add_return(incrs, &sp->max_val[id]);
62}
63
64/**
65 * Updated the value sent to hardware.
66 */
67static inline u32 nvhost_syncpt_set_max(struct nvhost_syncpt *sp,
68 u32 id, u32 val)
69{
70 atomic_set(&sp->max_val[id], val);
71 smp_wmb();
72 return val;
73}
74
75static inline u32 nvhost_syncpt_read_max(struct nvhost_syncpt *sp, u32 id)
76{
77 smp_rmb();
78 return (u32)atomic_read(&sp->max_val[id]);
79}
80
81static inline u32 nvhost_syncpt_read_min(struct nvhost_syncpt *sp, u32 id)
82{
83 smp_rmb();
84 return (u32)atomic_read(&sp->min_val[id]);
85}
86
87static inline bool nvhost_syncpt_check_max(struct nvhost_syncpt *sp,
88 u32 id, u32 real)
89{
90 u32 max;
91 if (client_managed(id))
92 return true;
93 max = nvhost_syncpt_read_max(sp, id);
94 return (s32)(max - real) >= 0;
95}
96
97/**
98 * Returns true if syncpoint min == max
99 */
100static inline bool nvhost_syncpt_min_eq_max(struct nvhost_syncpt *sp, u32 id)
101{
102 int min, max;
103 smp_rmb();
104 min = atomic_read(&sp->min_val[id]);
105 max = atomic_read(&sp->max_val[id]);
106 return (min == max);
107}
108
109void nvhost_syncpt_cpu_incr(struct nvhost_syncpt *sp, u32 id);
110
111u32 nvhost_syncpt_update_min(struct nvhost_syncpt *sp, u32 id);
112bool nvhost_syncpt_is_expired(struct nvhost_syncpt *sp, u32 id, u32 thresh);
113
114void nvhost_syncpt_save(struct nvhost_syncpt *sp);
115
116void nvhost_syncpt_reset(struct nvhost_syncpt *sp);
117
118u32 nvhost_syncpt_read(struct nvhost_syncpt *sp, u32 id);
119u32 nvhost_syncpt_read_wait_base(struct nvhost_syncpt *sp, u32 id);
120
121void nvhost_syncpt_incr(struct nvhost_syncpt *sp, u32 id);
122
123int nvhost_syncpt_wait_timeout(struct nvhost_syncpt *sp, u32 id, u32 thresh,
124 u32 timeout, u32 *value);
125
126static inline int nvhost_syncpt_wait(struct nvhost_syncpt *sp, u32 id, u32 thresh)
127{
128 return nvhost_syncpt_wait_timeout(sp, id, thresh,
129 MAX_SCHEDULE_TIMEOUT, NULL);
130}
131
132/*
133 * Check driver supplied waitchk structs for syncpt thresholds
134 * that have already been satisfied and NULL the comparison (to
135 * avoid a wrap condition in the HW).
136 *
137 * @param: sp - global shadowed syncpt struct
138 * @param: nvmap - needed to access command buffer
139 * @param: mask - bit mask of syncpt IDs referenced in WAITs
140 * @param: wait - start of filled in array of waitchk structs
141 * @param: waitend - end ptr (one beyond last valid waitchk)
142 */
143int nvhost_syncpt_wait_check(struct nvhost_syncpt *sp,
144 struct nvmap_client *nvmap,
145 u32 mask,
146 struct nvhost_waitchk *wait,
147 int num_waitchk);
148
149void nvhost_syncpt_debug(struct nvhost_syncpt *sp);
150
151int nvhost_mutex_try_lock(struct nvhost_syncpt *sp, int idx);
152
153void nvhost_mutex_unlock(struct nvhost_syncpt *sp, int idx);
154
155#endif
diff --git a/drivers/video/tegra/host/t20/Makefile b/drivers/video/tegra/host/t20/Makefile
new file mode 100644
index 00000000000..c2ade9bf925
--- /dev/null
+++ b/drivers/video/tegra/host/t20/Makefile
@@ -0,0 +1,8 @@
1GCOV_PROFILE := y
2
3EXTRA_CFLAGS += -Idrivers/video/tegra/host
4
5nvhost-t20-objs = \
6 t20.o
7
8obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t20.o
diff --git a/drivers/video/tegra/host/t20/t20.c b/drivers/video/tegra/host/t20/t20.c
new file mode 100644
index 00000000000..24ddedc842e
--- /dev/null
+++ b/drivers/video/tegra/host/t20/t20.c
@@ -0,0 +1,233 @@
1/*
2 * drivers/video/tegra/host/t20/t20.c
3 *
4 * Tegra Graphics Init for T20 Architecture Chips
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/slab.h>
22#include <mach/powergate.h>
23#include "dev.h"
24#include "t20.h"
25#include "host1x/host1x_channel.h"
26#include "host1x/host1x_syncpt.h"
27#include "host1x/host1x_hardware.h"
28#include "host1x/host1x_cdma.h"
29#include "gr3d/gr3d.h"
30#include "gr3d/gr3d_t20.h"
31#include "mpe/mpe.h"
32#include "nvhost_hwctx.h"
33
34#define NVMODMUTEX_2D_FULL (1)
35#define NVMODMUTEX_2D_SIMPLE (2)
36#define NVMODMUTEX_2D_SB_A (3)
37#define NVMODMUTEX_2D_SB_B (4)
38#define NVMODMUTEX_3D (5)
39#define NVMODMUTEX_DISPLAYA (6)
40#define NVMODMUTEX_DISPLAYB (7)
41#define NVMODMUTEX_VI (8)
42#define NVMODMUTEX_DSI (9)
43
44#define NVHOST_NUMCHANNELS (NV_HOST1X_CHANNELS - 1)
45
46struct nvhost_device t20_devices[] = {
47{
48 /* channel 0 */
49 .name = "display",
50 .id = -1,
51 .index = 0,
52 .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
53 BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) |
54 BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) |
55 BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
56 .modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB),
57 NVHOST_MODULE_NO_POWERGATE_IDS,
58 NVHOST_DEFAULT_CLOCKGATE_DELAY,
59 .moduleid = NVHOST_MODULE_NONE,
60},
61{
62 /* channel 1 */
63 .name = "gr3d",
64 .id = -1,
65 .index = 1,
66 .syncpts = BIT(NVSYNCPT_3D),
67 .waitbases = BIT(NVWAITBASE_3D),
68 .modulemutexes = BIT(NVMODMUTEX_3D),
69 .class = NV_GRAPHICS_3D_CLASS_ID,
70 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
71 .alloc_hwctx_handler = nvhost_gr3d_t20_ctxhandler_init,
72 .clocks = {{"gr3d", UINT_MAX}, {"emc", UINT_MAX}, {} },
73 .powergate_ids = {TEGRA_POWERGATE_3D, -1},
74 NVHOST_DEFAULT_CLOCKGATE_DELAY,
75 .moduleid = NVHOST_MODULE_NONE,
76},
77{
78 /* channel 2 */
79 .name = "gr2d",
80 .id = -1,
81 .index = 2,
82 .syncpts = BIT(NVSYNCPT_2D_0) | BIT(NVSYNCPT_2D_1),
83 .waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
84 .modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
85 BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
86 .clocks = { {"gr2d", UINT_MAX},
87 {"epp", UINT_MAX},
88 {"emc", UINT_MAX} },
89 NVHOST_MODULE_NO_POWERGATE_IDS,
90 .clockgate_delay = 0,
91 .moduleid = NVHOST_MODULE_NONE,
92},
93{
94 /* channel 3 */
95 .name = "isp",
96 .id = -1,
97 .index = 3,
98 .syncpts = 0,
99 NVHOST_MODULE_NO_POWERGATE_IDS,
100 NVHOST_DEFAULT_CLOCKGATE_DELAY,
101 .moduleid = NVHOST_MODULE_ISP,
102},
103{
104 /* channel 4 */
105 .name = "vi",
106 .id = -1,
107 .index = 4,
108 .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
109 BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
110 BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
111 BIT(NVSYNCPT_VI_ISP_4),
112 .modulemutexes = BIT(NVMODMUTEX_VI),
113 .exclusive = true,
114 NVHOST_MODULE_NO_POWERGATE_IDS,
115 NVHOST_DEFAULT_CLOCKGATE_DELAY,
116 .moduleid = NVHOST_MODULE_VI,
117},
118{
119 /* channel 5 */
120 .name = "mpe",
121 .id = -1,
122 .index = 5,
123 .syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
124 BIT(NVSYNCPT_MPE_WR_SAFE),
125 .waitbases = BIT(NVWAITBASE_MPE),
126 .class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
127 .waitbasesync = true,
128 .keepalive = true,
129 .prepare_poweroff = nvhost_mpe_prepare_power_off,
130 .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
131 .clocks = { {"mpe", UINT_MAX},
132 {"emc", UINT_MAX} },
133 .powergate_ids = {TEGRA_POWERGATE_MPE, -1},
134 NVHOST_DEFAULT_CLOCKGATE_DELAY,
135 .moduleid = NVHOST_MODULE_MPE,
136},
137{
138 /* channel 6 */
139 .name = "dsi",
140 .id = -1,
141 .index = 6,
142 .syncpts = BIT(NVSYNCPT_DSI),
143 .modulemutexes = BIT(NVMODMUTEX_DSI),
144 NVHOST_MODULE_NO_POWERGATE_IDS,
145 NVHOST_DEFAULT_CLOCKGATE_DELAY,
146 .moduleid = NVHOST_MODULE_NONE,
147} };
148
149
150static inline void __iomem *t20_channel_aperture(void __iomem *p, int ndx)
151{
152 p += NV_HOST1X_CHANNEL0_BASE;
153 p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
154 return p;
155}
156
157static inline int t20_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
158{
159 int err = 0;
160 unsigned long syncpts = ch->dev->syncpts;
161 unsigned long waitbases = ch->dev->waitbases;
162 u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
163 u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
164
165 if (ch->dev->alloc_hwctx_handler) {
166 ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
167 waitbase, ch);
168 if (!ch->ctxhandler)
169 err = -ENOMEM;
170 }
171
172 return err;
173}
174
175static int t20_channel_init(struct nvhost_channel *ch,
176 struct nvhost_master *dev, int index)
177{
178 ch->chid = index;
179 mutex_init(&ch->reflock);
180 mutex_init(&ch->submitlock);
181
182 ch->aperture = t20_channel_aperture(dev->aperture, index);
183
184 return t20_nvhost_hwctx_handler_init(ch);
185}
186
187int nvhost_init_t20_channel_support(struct nvhost_master *host)
188{
189 host->nb_channels = NVHOST_NUMCHANNELS;
190
191 host->op.channel.init = t20_channel_init;
192 host->op.channel.submit = host1x_channel_submit;
193 host->op.channel.read3dreg = host1x_channel_read_3d_reg;
194
195 return 0;
196}
197
198struct nvhost_device *t20_get_nvhost_device(struct nvhost_master *host,
199 char *name)
200{
201 int i;
202
203 for (i = 0; i < host->nb_channels; i++) {
204 if (strcmp(t20_devices[i].name, name) == 0)
205 return &t20_devices[i];
206 }
207
208 return NULL;
209}
210
211int nvhost_init_t20_support(struct nvhost_master *host)
212{
213 int err;
214
215 /* don't worry about cleaning up on failure... "remove" does it. */
216 err = nvhost_init_t20_channel_support(host);
217 if (err)
218 return err;
219 err = host1x_init_cdma_support(host);
220 if (err)
221 return err;
222 err = nvhost_init_t20_debug_support(host);
223 if (err)
224 return err;
225 err = host1x_init_syncpt_support(host);
226 if (err)
227 return err;
228 err = nvhost_init_t20_intr_support(host);
229 if (err)
230 return err;
231 host->op.nvhost_dev.get_nvhost_device = t20_get_nvhost_device;
232 return 0;
233}
diff --git a/drivers/video/tegra/host/t20/t20.h b/drivers/video/tegra/host/t20/t20.h
new file mode 100644
index 00000000000..93555a55b58
--- /dev/null
+++ b/drivers/video/tegra/host/t20/t20.h
@@ -0,0 +1,33 @@
1/*
2 * drivers/video/tegra/host/t20/t20.h
3 *
4 * Tegra Graphics Chip support for T20
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#ifndef _NVHOST_T20_H_
21#define _NVHOST_T20_H_
22
23struct nvhost_master;
24struct nvhost_module;
25
26int nvhost_init_t20_channel_support(struct nvhost_master *);
27int nvhost_init_t20_debug_support(struct nvhost_master *);
28int nvhost_init_t20_syncpt_support(struct nvhost_master *);
29int nvhost_init_t20_intr_support(struct nvhost_master *);
30int nvhost_init_t20_support(struct nvhost_master *host);
31int nvhost_t20_save_context(struct nvhost_module *mod, u32 syncpt_id);
32
33#endif /* _NVHOST_T20_H_ */
diff --git a/drivers/video/tegra/host/t30/Makefile b/drivers/video/tegra/host/t30/Makefile
new file mode 100644
index 00000000000..b343eb4fc7c
--- /dev/null
+++ b/drivers/video/tegra/host/t30/Makefile
@@ -0,0 +1,8 @@
1GCOV_PROFILE := y
2
3EXTRA_CFLAGS += -Idrivers/video/tegra/host
4
5nvhost-t30-objs = \
6 t30.o
7
8obj-$(CONFIG_TEGRA_GRHOST) += nvhost-t30.o
diff --git a/drivers/video/tegra/host/t30/t30.c b/drivers/video/tegra/host/t30/t30.c
new file mode 100644
index 00000000000..8a8b1f4d924
--- /dev/null
+++ b/drivers/video/tegra/host/t30/t30.c
@@ -0,0 +1,251 @@
1/*
2 * drivers/video/tegra/host/t30/t30.c
3 *
4 * Tegra Graphics Init for T30 Architecture Chips
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <linux/mutex.h>
22#include <mach/powergate.h>
23#include <mach/iomap.h>
24#include "dev.h"
25#include "t20/t20.h"
26#include "t30.h"
27#include "gr3d/gr3d.h"
28#include "mpe/mpe.h"
29#include "gr3d/gr3d_t30.h"
30#include "gr3d/scale3d.h"
31#include "host1x/host1x_hardware.h"
32#include "host1x/host1x_cdma.h"
33#include "host1x/host1x_syncpt.h"
34#include "chip_support.h"
35
36#define NVMODMUTEX_2D_FULL (1)
37#define NVMODMUTEX_2D_SIMPLE (2)
38#define NVMODMUTEX_2D_SB_A (3)
39#define NVMODMUTEX_2D_SB_B (4)
40#define NVMODMUTEX_3D (5)
41#define NVMODMUTEX_DISPLAYA (6)
42#define NVMODMUTEX_DISPLAYB (7)
43#define NVMODMUTEX_VI (8)
44#define NVMODMUTEX_DSI (9)
45
46#define NVHOST_CHANNEL_BASE 0
47
48struct nvhost_device t30_devices[] = {
49{
50 /* channel 0 */
51 .name = "display",
52 .id = -1,
53 .index = 0,
54 .syncpts = BIT(NVSYNCPT_DISP0_A) | BIT(NVSYNCPT_DISP1_A) |
55 BIT(NVSYNCPT_DISP0_B) | BIT(NVSYNCPT_DISP1_B) |
56 BIT(NVSYNCPT_DISP0_C) | BIT(NVSYNCPT_DISP1_C) |
57 BIT(NVSYNCPT_VBLANK0) | BIT(NVSYNCPT_VBLANK1),
58 .modulemutexes = BIT(NVMODMUTEX_DISPLAYA) | BIT(NVMODMUTEX_DISPLAYB),
59 NVHOST_MODULE_NO_POWERGATE_IDS,
60 NVHOST_DEFAULT_CLOCKGATE_DELAY,
61 .moduleid = NVHOST_MODULE_NONE,
62},
63{
64 /* channel 1 */
65 .name = "gr3d",
66 .id = -1,
67 .index = 1,
68 .syncpts = BIT(NVSYNCPT_3D),
69 .waitbases = BIT(NVWAITBASE_3D),
70 .modulemutexes = BIT(NVMODMUTEX_3D),
71 .class = NV_GRAPHICS_3D_CLASS_ID,
72 .prepare_poweroff = nvhost_gr3d_prepare_power_off,
73 .busy = nvhost_scale3d_notify_busy,
74 .idle = nvhost_scale3d_notify_idle,
75 .init = nvhost_scale3d_init,
76 .deinit = nvhost_scale3d_deinit,
77 .suspend = nvhost_scale3d_suspend,
78 .alloc_hwctx_handler = nvhost_gr3d_t30_ctxhandler_init,
79 .clocks = { {"gr3d", UINT_MAX},
80 {"gr3d2", UINT_MAX},
81 {"emc", UINT_MAX} },
82 .powergate_ids = { TEGRA_POWERGATE_3D,
83 TEGRA_POWERGATE_3D1 },
84 NVHOST_DEFAULT_CLOCKGATE_DELAY,
85 .can_powergate = false,
86 .powergate_delay = 250,
87 .moduleid = NVHOST_MODULE_NONE,
88},
89{
90 /* channel 2 */
91 .name = "gr2d",
92 .id = -1,
93 .index = 2,
94 .syncpts = BIT(NVSYNCPT_2D_0) | BIT(NVSYNCPT_2D_1),
95 .waitbases = BIT(NVWAITBASE_2D_0) | BIT(NVWAITBASE_2D_1),
96 .modulemutexes = BIT(NVMODMUTEX_2D_FULL) | BIT(NVMODMUTEX_2D_SIMPLE) |
97 BIT(NVMODMUTEX_2D_SB_A) | BIT(NVMODMUTEX_2D_SB_B),
98 .clocks = { {"gr2d", 0},
99 {"epp", 0},
100 {"emc", 300000000} },
101 NVHOST_MODULE_NO_POWERGATE_IDS,
102 .clockgate_delay = 0,
103 .moduleid = NVHOST_MODULE_NONE,
104},
105{
106 /* channel 3 */
107 .name = "isp",
108 .id = -1,
109 .index = 3,
110 .syncpts = 0,
111 NVHOST_MODULE_NO_POWERGATE_IDS,
112 NVHOST_DEFAULT_CLOCKGATE_DELAY,
113 .moduleid = NVHOST_MODULE_ISP,
114},
115{
116 /* channel 4 */
117 .name = "vi",
118 .id = -1,
119 .index = 4,
120 .syncpts = BIT(NVSYNCPT_CSI_VI_0) | BIT(NVSYNCPT_CSI_VI_1) |
121 BIT(NVSYNCPT_VI_ISP_0) | BIT(NVSYNCPT_VI_ISP_1) |
122 BIT(NVSYNCPT_VI_ISP_2) | BIT(NVSYNCPT_VI_ISP_3) |
123 BIT(NVSYNCPT_VI_ISP_4),
124 .modulemutexes = BIT(NVMODMUTEX_VI),
125 .exclusive = true,
126 NVHOST_MODULE_NO_POWERGATE_IDS,
127 NVHOST_DEFAULT_CLOCKGATE_DELAY,
128 .moduleid = NVHOST_MODULE_VI,
129},
130{
131 /* channel 5 */
132 .name = "mpe",
133 .id = -1,
134 .index = 5,
135 .syncpts = BIT(NVSYNCPT_MPE) | BIT(NVSYNCPT_MPE_EBM_EOF) |
136 BIT(NVSYNCPT_MPE_WR_SAFE),
137 .waitbases = BIT(NVWAITBASE_MPE),
138 .class = NV_VIDEO_ENCODE_MPEG_CLASS_ID,
139 .waitbasesync = true,
140 .keepalive = true,
141 .prepare_poweroff = nvhost_mpe_prepare_power_off,
142 .alloc_hwctx_handler = nvhost_mpe_ctxhandler_init,
143 .clocks = { {"mpe", UINT_MAX},
144 {"emc", UINT_MAX} },
145 .powergate_ids = {TEGRA_POWERGATE_MPE, -1},
146 NVHOST_DEFAULT_CLOCKGATE_DELAY,
147 .can_powergate = true,
148 .powergate_delay = 100,
149 .moduleid = NVHOST_MODULE_MPE,
150},
151{
152 /* channel 6 */
153 .name = "dsi",
154 .id = -1,
155 .index = 6,
156 .syncpts = BIT(NVSYNCPT_DSI),
157 .modulemutexes = BIT(NVMODMUTEX_DSI),
158 NVHOST_MODULE_NO_POWERGATE_IDS,
159 NVHOST_DEFAULT_CLOCKGATE_DELAY,
160 .moduleid = NVHOST_MODULE_NONE,
161} };
162
163static inline int t30_nvhost_hwctx_handler_init(struct nvhost_channel *ch)
164{
165 int err = 0;
166 unsigned long syncpts = ch->dev->syncpts;
167 unsigned long waitbases = ch->dev->waitbases;
168 u32 syncpt = find_first_bit(&syncpts, BITS_PER_LONG);
169 u32 waitbase = find_first_bit(&waitbases, BITS_PER_LONG);
170
171 if (ch->dev->alloc_hwctx_handler) {
172 ch->ctxhandler = ch->dev->alloc_hwctx_handler(syncpt,
173 waitbase, ch);
174 if (!ch->ctxhandler)
175 err = -ENOMEM;
176 }
177
178 return err;
179}
180
181static inline void __iomem *t30_channel_aperture(void __iomem *p, int ndx)
182{
183 ndx += NVHOST_CHANNEL_BASE;
184 p += NV_HOST1X_CHANNEL0_BASE;
185 p += ndx * NV_HOST1X_CHANNEL_MAP_SIZE_BYTES;
186 return p;
187}
188
189static int t30_channel_init(struct nvhost_channel *ch,
190 struct nvhost_master *dev, int index)
191{
192 ch->chid = index;
193 mutex_init(&ch->reflock);
194 mutex_init(&ch->submitlock);
195
196 ch->aperture = t30_channel_aperture(dev->aperture, index);
197
198 return t30_nvhost_hwctx_handler_init(ch);
199}
200
201int nvhost_init_t30_channel_support(struct nvhost_master *host)
202{
203 int result = nvhost_init_t20_channel_support(host);
204 host->op.channel.init = t30_channel_init;
205
206 return result;
207}
208int nvhost_init_t30_debug_support(struct nvhost_master *host)
209{
210 nvhost_init_t20_debug_support(host);
211 host->op.debug.debug_init = nvhost_scale3d_debug_init;
212
213 return 0;
214}
215
216struct nvhost_device *t30_get_nvhost_device(struct nvhost_master *host,
217 char *name)
218{
219 int i;
220
221 for (i = 0; i < host->nb_channels; i++) {
222 if (strcmp(t30_devices[i].name, name) == 0)
223 return &t30_devices[i];
224 }
225
226 return NULL;
227}
228
229int nvhost_init_t30_support(struct nvhost_master *host)
230{
231 int err;
232
233 /* don't worry about cleaning up on failure... "remove" does it. */
234 err = nvhost_init_t30_channel_support(host);
235 if (err)
236 return err;
237 err = host1x_init_cdma_support(host);
238 if (err)
239 return err;
240 err = nvhost_init_t30_debug_support(host);
241 if (err)
242 return err;
243 err = host1x_init_syncpt_support(host);
244 if (err)
245 return err;
246 err = nvhost_init_t20_intr_support(host);
247 if (err)
248 return err;
249 host->op.nvhost_dev.get_nvhost_device = t30_get_nvhost_device;
250 return 0;
251}
diff --git a/drivers/video/tegra/host/t30/t30.h b/drivers/video/tegra/host/t30/t30.h
new file mode 100644
index 00000000000..0446dbd19b3
--- /dev/null
+++ b/drivers/video/tegra/host/t30/t30.h
@@ -0,0 +1,29 @@
1/*
2 * drivers/video/tegra/host/t30/t30.h
3 *
4 * Tegra Graphics Chip support for Tegra3
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20#ifndef _NVHOST_T30_H_
21#define _NVHOST_T30_H_
22
23struct nvhost_master;
24
25int nvhost_init_t30_channel_support(struct nvhost_master *);
26int nvhost_init_t30_debug_support(struct nvhost_master *);
27int nvhost_init_t30_support(struct nvhost_master *host);
28
29#endif /* _NVHOST_T30_H_ */
diff --git a/drivers/video/tegra/host/vi/Makefile b/drivers/video/tegra/host/vi/Makefile
new file mode 100644
index 00000000000..8c130e49814
--- /dev/null
+++ b/drivers/video/tegra/host/vi/Makefile
@@ -0,0 +1,7 @@
1GCOV_PROFILE := y
2EXTRA_CFLAGS += -Idrivers/video/tegra/host
3
4nvhost-vi-objs = \
5 vi.o
6
7obj-$(CONFIG_TEGRA_GRHOST) += nvhost-vi.o
diff --git a/drivers/video/tegra/host/vi/vi.c b/drivers/video/tegra/host/vi/vi.c
new file mode 100644
index 00000000000..71d517152ad
--- /dev/null
+++ b/drivers/video/tegra/host/vi/vi.c
@@ -0,0 +1,82 @@
1/*
2 * drivers/video/tegra/host/vi/vi.c
3 *
4 * Tegra Graphics Host VI
5 *
6 * Copyright (c) 2012, NVIDIA Corporation.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms and conditions of the GNU General Public License,
10 * version 2, as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "dev.h"
22#include "bus_client.h"
23
24static int __devinit vi_probe(struct nvhost_device *dev)
25{
26 return nvhost_client_device_init(dev);
27}
28
29static int __exit vi_remove(struct nvhost_device *dev)
30{
31 /* Add clean-up */
32 return 0;
33}
34
35static int vi_suspend(struct nvhost_device *dev, pm_message_t state)
36{
37 return nvhost_client_device_suspend(dev);
38}
39
40static int vi_resume(struct nvhost_device *dev)
41{
42 dev_info(&dev->dev, "resuming\n");
43 return 0;
44}
45
46struct nvhost_device *vi_device;
47
48static struct nvhost_driver vi_driver = {
49 .probe = vi_probe,
50 .remove = __exit_p(vi_remove),
51#ifdef CONFIG_PM
52 .suspend = vi_suspend,
53 .resume = vi_resume,
54#endif
55 .driver = {
56 .owner = THIS_MODULE,
57 .name = "vi",
58 }
59};
60
61static int __init vi_init(void)
62{
63 int err;
64
65 vi_device = nvhost_get_device("vi");
66 if (!vi_device)
67 return -ENXIO;
68
69 err = nvhost_device_register(vi_device);
70 if (err)
71 return err;
72
73 return nvhost_driver_register(&vi_driver);
74}
75
76static void __exit vi_exit(void)
77{
78 nvhost_driver_unregister(&vi_driver);
79}
80
81module_init(vi_init);
82module_exit(vi_exit);
diff --git a/drivers/video/tegra/nvmap/Makefile b/drivers/video/tegra/nvmap/Makefile
new file mode 100644
index 00000000000..95d7f68836a
--- /dev/null
+++ b/drivers/video/tegra/nvmap/Makefile
@@ -0,0 +1,7 @@
1GCOV_PROFILE := y
2obj-y += nvmap.o
3obj-y += nvmap_dev.o
4obj-y += nvmap_handle.o
5obj-y += nvmap_heap.o
6obj-y += nvmap_ioctl.o
7obj-${CONFIG_NVMAP_RECLAIM_UNPINNED_VM} += nvmap_mru.o \ No newline at end of file
diff --git a/drivers/video/tegra/nvmap/nvmap.c b/drivers/video/tegra/nvmap/nvmap.c
new file mode 100644
index 00000000000..b4b6241618d
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap.c
@@ -0,0 +1,871 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap.c
3 *
4 * Memory manager for Tegra GPU
5 *
6 * Copyright (c) 2009-2011, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/err.h>
24#include <linux/highmem.h>
25#include <linux/io.h>
26#include <linux/rbtree.h>
27#include <linux/vmalloc.h>
28#include <linux/wait.h>
29#include <linux/slab.h>
30
31#include <asm/pgtable.h>
32#include <asm/tlbflush.h>
33
34#include <mach/iovmm.h>
35#include <mach/nvmap.h>
36
37#include "nvmap.h"
38#include "nvmap_mru.h"
39
40/* private nvmap_handle flag for pinning duplicate detection */
41#define NVMAP_HANDLE_VISITED (0x1ul << 31)
42
43/* map the backing pages for a heap_pgalloc handle into its IOVMM area */
44static void map_iovmm_area(struct nvmap_handle *h)
45{
46 tegra_iovmm_addr_t va;
47 unsigned long i;
48
49 BUG_ON(!h->heap_pgalloc || !h->pgalloc.area);
50 BUG_ON(h->size & ~PAGE_MASK);
51 WARN_ON(!h->pgalloc.dirty);
52
53 for (va = h->pgalloc.area->iovm_start, i = 0;
54 va < (h->pgalloc.area->iovm_start + h->size);
55 i++, va += PAGE_SIZE) {
56 BUG_ON(!pfn_valid(page_to_pfn(h->pgalloc.pages[i])));
57 tegra_iovmm_vm_insert_pfn(h->pgalloc.area, va,
58 page_to_pfn(h->pgalloc.pages[i]));
59 }
60 h->pgalloc.dirty = false;
61}
62
63/* must be called inside nvmap_pin_lock, to ensure that an entire stream
64 * of pins will complete without racing with a second stream. handle should
65 * have nvmap_handle_get (or nvmap_validate_get) called before calling
66 * this function. */
67static int pin_locked(struct nvmap_client *client, struct nvmap_handle *h)
68{
69 struct tegra_iovmm_area *area;
70 BUG_ON(!h->alloc);
71
72 nvmap_mru_lock(client->share);
73 if (atomic_inc_return(&h->pin) == 1) {
74 if (h->heap_pgalloc && !h->pgalloc.contig) {
75 area = nvmap_handle_iovmm_locked(client, h);
76 if (!area) {
77 /* no race here, inside the pin mutex */
78 atomic_dec(&h->pin);
79 nvmap_mru_unlock(client->share);
80 return -ENOMEM;
81 }
82 if (area != h->pgalloc.area)
83 h->pgalloc.dirty = true;
84 h->pgalloc.area = area;
85 }
86 }
87 nvmap_mru_unlock(client->share);
88 return 0;
89}
90
91/* doesn't need to be called inside nvmap_pin_lock, since this will only
92 * expand the available VM area */
93static int handle_unpin(struct nvmap_client *client,
94 struct nvmap_handle *h, int free_vm)
95{
96 int ret = 0;
97 nvmap_mru_lock(client->share);
98
99 if (atomic_read(&h->pin) == 0) {
100 nvmap_err(client, "%s unpinning unpinned handle %p\n",
101 current->group_leader->comm, h);
102 nvmap_mru_unlock(client->share);
103 return 0;
104 }
105
106 BUG_ON(!h->alloc);
107
108 if (!atomic_dec_return(&h->pin)) {
109 if (h->heap_pgalloc && h->pgalloc.area) {
110 /* if a secure handle is clean (i.e., mapped into
111 * IOVMM, it needs to be zapped on unpin. */
112 if (h->secure && !h->pgalloc.dirty) {
113 tegra_iovmm_zap_vm(h->pgalloc.area);
114 h->pgalloc.dirty = true;
115 }
116 if (free_vm) {
117 tegra_iovmm_free_vm(h->pgalloc.area);
118 h->pgalloc.area = NULL;
119 } else
120 nvmap_mru_insert_locked(client->share, h);
121 ret = 1;
122 }
123 }
124
125 nvmap_mru_unlock(client->share);
126 nvmap_handle_put(h);
127 return ret;
128}
129
130static int pin_array_locked(struct nvmap_client *client,
131 struct nvmap_handle **h, int count)
132{
133 int pinned;
134 int i;
135 int err = 0;
136
137 for (pinned = 0; pinned < count; pinned++) {
138 err = pin_locked(client, h[pinned]);
139 if (err)
140 break;
141 }
142
143 if (err) {
144 /* unpin pinned handles */
145 for (i = 0; i < pinned; i++) {
146 /* inc ref counter, because
147 * handle_unpin decrements it */
148 nvmap_handle_get(h[i]);
149 /* unpin handles and free vm */
150 handle_unpin(client, h[i], true);
151 }
152 }
153
154 if (err && tegra_iovmm_get_max_free(client->share->iovmm) >=
155 client->iovm_limit) {
156 /* First attempt to pin in empty iovmm
157 * may still fail because of fragmentation caused by
158 * placing handles in MRU areas. After such failure
159 * all MRU gets cleaned and iovm space is freed.
160 *
161 * We have to do pinning again here since there might be is
162 * no more incoming pin_wait wakeup calls from unpin
163 * operations */
164 for (pinned = 0; pinned < count; pinned++) {
165 err = pin_locked(client, h[pinned]);
166 if (err)
167 break;
168 }
169 if (err) {
170 pr_err("Pinning in empty iovmm failed!!!\n");
171 BUG_ON(1);
172 }
173 }
174 return err;
175}
176
177static int wait_pin_array_locked(struct nvmap_client *client,
178 struct nvmap_handle **h, int count)
179{
180 int ret = 0;
181
182 ret = pin_array_locked(client, h, count);
183
184 if (ret) {
185 ret = wait_event_interruptible(client->share->pin_wait,
186 !pin_array_locked(client, h, count));
187 }
188 return ret ? -EINTR : 0;
189}
190
191static int handle_unpin_noref(struct nvmap_client *client, unsigned long id)
192{
193 struct nvmap_handle *h;
194 int w;
195
196 h = nvmap_validate_get(client, id);
197 if (unlikely(!h)) {
198 nvmap_err(client, "%s attempting to unpin invalid handle %p\n",
199 current->group_leader->comm, (void *)id);
200 return 0;
201 }
202
203 nvmap_err(client, "%s unpinning unreferenced handle %p\n",
204 current->group_leader->comm, h);
205 WARN_ON(1);
206
207 w = handle_unpin(client, h, false);
208 nvmap_handle_put(h);
209 return w;
210}
211
212void nvmap_unpin_ids(struct nvmap_client *client,
213 unsigned int nr, const unsigned long *ids)
214{
215 unsigned int i;
216 int do_wake = 0;
217
218 for (i = 0; i < nr; i++) {
219 struct nvmap_handle_ref *ref;
220
221 if (!ids[i])
222 continue;
223
224 nvmap_ref_lock(client);
225 ref = _nvmap_validate_id_locked(client, ids[i]);
226 if (ref) {
227 struct nvmap_handle *h = ref->handle;
228 int e = atomic_add_unless(&ref->pin, -1, 0);
229
230 nvmap_ref_unlock(client);
231
232 if (!e) {
233 nvmap_err(client, "%s unpinning unpinned "
234 "handle %08lx\n",
235 current->group_leader->comm, ids[i]);
236 } else {
237 do_wake |= handle_unpin(client, h, false);
238 }
239 } else {
240 nvmap_ref_unlock(client);
241 if (client->super)
242 do_wake |= handle_unpin_noref(client, ids[i]);
243 else
244 nvmap_err(client, "%s unpinning invalid "
245 "handle %08lx\n",
246 current->group_leader->comm, ids[i]);
247 }
248 }
249
250 if (do_wake)
251 wake_up(&client->share->pin_wait);
252}
253
254/* pins a list of handle_ref objects; same conditions apply as to
255 * _nvmap_handle_pin, but also bumps the pin count of each handle_ref. */
256int nvmap_pin_ids(struct nvmap_client *client,
257 unsigned int nr, const unsigned long *ids)
258{
259 int ret = 0;
260 unsigned int i;
261 struct nvmap_handle **h = (struct nvmap_handle **)ids;
262 struct nvmap_handle_ref *ref;
263
264 /* to optimize for the common case (client provided valid handle
265 * references and the pin succeeds), increment the handle_ref pin
266 * count during validation. in error cases, the tree will need to
267 * be re-walked, since the handle_ref is discarded so that an
268 * allocation isn't required. if a handle_ref is not found,
269 * locally validate that the caller has permission to pin the handle;
270 * handle_refs are not created in this case, so it is possible that
271 * if the caller crashes after pinning a global handle, the handle
272 * will be permanently leaked. */
273 nvmap_ref_lock(client);
274 for (i = 0; i < nr && !ret; i++) {
275 ref = _nvmap_validate_id_locked(client, ids[i]);
276 if (ref) {
277 atomic_inc(&ref->pin);
278 nvmap_handle_get(h[i]);
279 } else {
280 struct nvmap_handle *verify;
281 nvmap_ref_unlock(client);
282 verify = nvmap_validate_get(client, ids[i]);
283 if (verify)
284 nvmap_warn(client, "%s pinning unreferenced "
285 "handle %p\n",
286 current->group_leader->comm, h[i]);
287 else
288 ret = -EPERM;
289 nvmap_ref_lock(client);
290 }
291 }
292 nvmap_ref_unlock(client);
293
294 nr = i;
295
296 if (ret)
297 goto out;
298
299 ret = mutex_lock_interruptible(&client->share->pin_lock);
300 if (WARN_ON(ret))
301 goto out;
302
303 ret = wait_pin_array_locked(client, h, nr);
304
305 mutex_unlock(&client->share->pin_lock);
306
307 if (ret) {
308 ret = -EINTR;
309 } else {
310 for (i = 0; i < nr; i++) {
311 if (h[i]->heap_pgalloc && h[i]->pgalloc.dirty)
312 map_iovmm_area(h[i]);
313 }
314 }
315
316out:
317 if (ret) {
318 nvmap_ref_lock(client);
319 for (i = 0; i < nr; i++) {
320 ref = _nvmap_validate_id_locked(client, ids[i]);
321 if (!ref) {
322 nvmap_warn(client, "%s freed handle %p "
323 "during pinning\n",
324 current->group_leader->comm,
325 (void *)ids[i]);
326 continue;
327 }
328 atomic_dec(&ref->pin);
329 }
330 nvmap_ref_unlock(client);
331
332 for (i = 0; i < nr; i++)
333 nvmap_handle_put(h[i]);
334 }
335
336 return ret;
337}
338
339static phys_addr_t handle_phys(struct nvmap_handle *h)
340{
341 phys_addr_t addr;
342
343 if (h->heap_pgalloc && h->pgalloc.contig) {
344 addr = page_to_phys(h->pgalloc.pages[0]);
345 } else if (h->heap_pgalloc) {
346 BUG_ON(!h->pgalloc.area);
347 addr = h->pgalloc.area->iovm_start;
348 } else {
349 addr = h->carveout->base;
350 }
351
352 return addr;
353}
354
355/* stores the physical address (+offset) of each handle relocation entry
356 * into its output location. see nvmap_pin_array for more details.
357 *
358 * each entry in arr (i.e., each relocation request) specifies two handles:
359 * the handle to pin (pin), and the handle where the address of pin should be
360 * written (patch). in pseudocode, this loop basically looks like:
361 *
362 * for (i = 0; i < nr; i++) {
363 * (pin, pin_offset, patch, patch_offset) = arr[i];
364 * patch[patch_offset] = address_of(pin) + pin_offset;
365 * }
366 */
367static int nvmap_reloc_pin_array(struct nvmap_client *client,
368 const struct nvmap_pinarray_elem *arr,
369 int nr, struct nvmap_handle *gather)
370{
371 struct nvmap_handle *last_patch = NULL;
372 unsigned int last_pfn = 0;
373 pte_t **pte;
374 void *addr;
375 int i;
376
377 pte = nvmap_alloc_pte(client->dev, &addr);
378 if (IS_ERR(pte))
379 return PTR_ERR(pte);
380
381 for (i = 0; i < nr; i++) {
382 struct nvmap_handle *patch;
383 struct nvmap_handle *pin;
384 phys_addr_t reloc_addr;
385 phys_addr_t phys;
386 unsigned int pfn;
387
388 /* all of the handles are validated and get'ted prior to
389 * calling this function, so casting is safe here */
390 pin = (struct nvmap_handle *)arr[i].pin_mem;
391
392 if (arr[i].patch_mem == (unsigned long)last_patch) {
393 patch = last_patch;
394 } else if (arr[i].patch_mem == (unsigned long)gather) {
395 patch = gather;
396 } else {
397 if (last_patch)
398 nvmap_handle_put(last_patch);
399
400 patch = nvmap_get_handle_id(client, arr[i].patch_mem);
401 if (!patch) {
402 nvmap_free_pte(client->dev, pte);
403 return -EPERM;
404 }
405 last_patch = patch;
406 }
407
408 if (patch->heap_pgalloc) {
409 unsigned int page = arr[i].patch_offset >> PAGE_SHIFT;
410 phys = page_to_phys(patch->pgalloc.pages[page]);
411 phys += (arr[i].patch_offset & ~PAGE_MASK);
412 } else {
413 phys = patch->carveout->base + arr[i].patch_offset;
414 }
415
416 pfn = __phys_to_pfn(phys);
417 if (pfn != last_pfn) {
418 pgprot_t prot = nvmap_pgprot(patch, pgprot_kernel);
419 phys_addr_t kaddr = (phys_addr_t)addr;
420 set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
421 flush_tlb_kernel_page(kaddr);
422 last_pfn = pfn;
423 }
424
425 reloc_addr = handle_phys(pin) + arr[i].pin_offset;
426 reloc_addr >>= arr[i].reloc_shift;
427 __raw_writel(reloc_addr, addr + (phys & ~PAGE_MASK));
428 }
429
430 nvmap_free_pte(client->dev, pte);
431
432 if (last_patch)
433 nvmap_handle_put(last_patch);
434
435 wmb();
436
437 return 0;
438}
439
440static int nvmap_validate_get_pin_array(struct nvmap_client *client,
441 const struct nvmap_pinarray_elem *arr,
442 int nr, struct nvmap_handle **h)
443{
444 int i;
445 int ret = 0;
446 int count = 0;
447
448 nvmap_ref_lock(client);
449
450 for (i = 0; i < nr; i++) {
451 struct nvmap_handle_ref *ref;
452
453 if (need_resched()) {
454 nvmap_ref_unlock(client);
455 schedule();
456 nvmap_ref_lock(client);
457 }
458
459 ref = _nvmap_validate_id_locked(client, arr[i].pin_mem);
460
461 if (!ref)
462 nvmap_warn(client, "falied to validate id\n");
463 else if (!ref->handle)
464 nvmap_warn(client, "id had no associated handle\n");
465 else if (!ref->handle->alloc)
466 nvmap_warn(client, "handle had no allocation\n");
467
468 if (!ref || !ref->handle || !ref->handle->alloc) {
469 ret = -EPERM;
470 break;
471 }
472
473 /* a handle may be referenced multiple times in arr, but
474 * it will only be pinned once; this ensures that the
475 * minimum number of sync-queue slots in the host driver
476 * are dedicated to storing unpin lists, which allows
477 * for greater parallelism between the CPU and graphics
478 * processor */
479 if (ref->handle->flags & NVMAP_HANDLE_VISITED)
480 continue;
481
482 ref->handle->flags |= NVMAP_HANDLE_VISITED;
483
484 h[count] = nvmap_handle_get(ref->handle);
485 BUG_ON(!h[count]);
486 count++;
487 }
488
489 nvmap_ref_unlock(client);
490
491 if (ret) {
492 for (i = 0; i < count; i++) {
493 h[i]->flags &= ~NVMAP_HANDLE_VISITED;
494 nvmap_handle_put(h[i]);
495 }
496 }
497
498 return ret ?: count;
499}
500
501/* a typical mechanism host1x clients use for using the Tegra graphics
502 * processor is to build a command buffer which contains relocatable
503 * memory handle commands, and rely on the kernel to convert these in-place
504 * to addresses which are understood by the GPU hardware.
505 *
506 * this is implemented by having clients provide a sideband array
507 * of relocatable handles (+ offsets) and the location in the command
508 * buffer handle to patch with the GPU address when the client submits
509 * its command buffer to the host1x driver.
510 *
511 * the host driver also uses this relocation mechanism internally to
512 * relocate the client's (unpinned) command buffers into host-addressable
513 * memory.
514 *
515 * @client: nvmap_client which should be used for validation; should be
516 * owned by the process which is submitting command buffers
517 * @gather: special handle for relocated command buffer outputs used
518 * internally by the host driver. if this handle is encountered
519 * as an output handle in the relocation array, it is assumed
520 * to be a known-good output and is not validated.
521 * @arr: array of ((relocatable handle, offset), (output handle, offset))
522 * tuples.
523 * @nr: number of entries in arr
524 * @unique_arr: list of nvmap_handle objects which were pinned by
525 * nvmap_pin_array. must be unpinned by the caller after the
526 * command buffers referenced in gather have completed.
527 */
528int nvmap_pin_array(struct nvmap_client *client, struct nvmap_handle *gather,
529 const struct nvmap_pinarray_elem *arr, int nr,
530 struct nvmap_handle **unique_arr)
531{
532 int count = 0;
533 int ret = 0;
534 int i;
535
536 if (mutex_lock_interruptible(&client->share->pin_lock)) {
537 nvmap_warn(client, "%s interrupted when acquiring pin lock\n",
538 current->group_leader->comm);
539 return -EINTR;
540 }
541
542 count = nvmap_validate_get_pin_array(client, arr, nr, unique_arr);
543 if (count < 0) {
544 mutex_unlock(&client->share->pin_lock);
545 nvmap_warn(client, "failed to validate pin array\n");
546 return count;
547 }
548
549 for (i = 0; i < count; i++)
550 unique_arr[i]->flags &= ~NVMAP_HANDLE_VISITED;
551
552 ret = wait_pin_array_locked(client, unique_arr, count);
553
554 mutex_unlock(&client->share->pin_lock);
555
556 if (!ret)
557 ret = nvmap_reloc_pin_array(client, arr, nr, gather);
558
559 if (WARN_ON(ret)) {
560 for (i = 0; i < count; i++)
561 nvmap_handle_put(unique_arr[i]);
562 return ret;
563 } else {
564 for (i = 0; i < count; i++) {
565 if (unique_arr[i]->heap_pgalloc &&
566 unique_arr[i]->pgalloc.dirty)
567 map_iovmm_area(unique_arr[i]);
568 }
569 }
570
571 return count;
572}
573
574phys_addr_t nvmap_pin(struct nvmap_client *client,
575 struct nvmap_handle_ref *ref)
576{
577 struct nvmap_handle *h;
578 phys_addr_t phys;
579 int ret = 0;
580
581 h = nvmap_handle_get(ref->handle);
582 if (WARN_ON(!h))
583 return -EINVAL;
584
585 atomic_inc(&ref->pin);
586
587 if (WARN_ON(mutex_lock_interruptible(&client->share->pin_lock))) {
588 ret = -EINTR;
589 } else {
590 ret = wait_pin_array_locked(client, &h, 1);
591 mutex_unlock(&client->share->pin_lock);
592 }
593
594 if (ret) {
595 atomic_dec(&ref->pin);
596 nvmap_handle_put(h);
597 } else {
598 if (h->heap_pgalloc && h->pgalloc.dirty)
599 map_iovmm_area(h);
600 phys = handle_phys(h);
601 }
602
603 return ret ?: phys;
604}
605
606phys_addr_t nvmap_handle_address(struct nvmap_client *c, unsigned long id)
607{
608 struct nvmap_handle *h;
609 phys_addr_t phys;
610
611 h = nvmap_get_handle_id(c, id);
612 if (!h)
613 return -EPERM;
614 mutex_lock(&h->lock);
615 phys = handle_phys(h);
616 mutex_unlock(&h->lock);
617 nvmap_handle_put(h);
618
619 return phys;
620}
621
622void nvmap_unpin(struct nvmap_client *client, struct nvmap_handle_ref *ref)
623{
624 if (!ref)
625 return;
626
627 atomic_dec(&ref->pin);
628 if (handle_unpin(client, ref->handle, false))
629 wake_up(&client->share->pin_wait);
630}
631
632void nvmap_unpin_handles(struct nvmap_client *client,
633 struct nvmap_handle **h, int nr)
634{
635 int i;
636 int do_wake = 0;
637
638 for (i = 0; i < nr; i++) {
639 if (WARN_ON(!h[i]))
640 continue;
641 do_wake |= handle_unpin(client, h[i], false);
642 }
643
644 if (do_wake)
645 wake_up(&client->share->pin_wait);
646}
647
648void *nvmap_mmap(struct nvmap_handle_ref *ref)
649{
650 struct nvmap_handle *h;
651 pgprot_t prot;
652 unsigned long adj_size;
653 unsigned long offs;
654 struct vm_struct *v;
655 void *p;
656
657 h = nvmap_handle_get(ref->handle);
658 if (!h)
659 return NULL;
660
661 prot = nvmap_pgprot(h, pgprot_kernel);
662
663 if (h->heap_pgalloc)
664 return vm_map_ram(h->pgalloc.pages, h->size >> PAGE_SHIFT,
665 -1, prot);
666
667 /* carveout - explicitly map the pfns into a vmalloc area */
668
669 nvmap_usecount_inc(h);
670
671 adj_size = h->carveout->base & ~PAGE_MASK;
672 adj_size += h->size;
673 adj_size = PAGE_ALIGN(adj_size);
674
675 v = alloc_vm_area(adj_size);
676 if (!v) {
677 nvmap_usecount_dec(h);
678 nvmap_handle_put(h);
679 return NULL;
680 }
681
682 p = v->addr + (h->carveout->base & ~PAGE_MASK);
683
684 for (offs = 0; offs < adj_size; offs += PAGE_SIZE) {
685 unsigned long addr = (unsigned long) v->addr + offs;
686 unsigned int pfn;
687 pgd_t *pgd;
688 pud_t *pud;
689 pmd_t *pmd;
690 pte_t *pte;
691
692 pfn = __phys_to_pfn(h->carveout->base + offs);
693 pgd = pgd_offset_k(addr);
694 pud = pud_alloc(&init_mm, pgd, addr);
695 if (!pud)
696 break;
697 pmd = pmd_alloc(&init_mm, pud, addr);
698 if (!pmd)
699 break;
700 pte = pte_alloc_kernel(pmd, addr);
701 if (!pte)
702 break;
703 set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
704 flush_tlb_kernel_page(addr);
705 }
706
707 if (offs != adj_size) {
708 free_vm_area(v);
709 nvmap_usecount_dec(h);
710 nvmap_handle_put(h);
711 return NULL;
712 }
713
714 /* leave the handle ref count incremented by 1, so that
715 * the handle will not be freed while the kernel mapping exists.
716 * nvmap_handle_put will be called by unmapping this address */
717 return p;
718}
719
720void nvmap_munmap(struct nvmap_handle_ref *ref, void *addr)
721{
722 struct nvmap_handle *h;
723
724 if (!ref)
725 return;
726
727 h = ref->handle;
728
729 if (h->heap_pgalloc) {
730 vm_unmap_ram(addr, h->size >> PAGE_SHIFT);
731 } else {
732 struct vm_struct *vm;
733 addr -= (h->carveout->base & ~PAGE_MASK);
734 vm = remove_vm_area(addr);
735 BUG_ON(!vm);
736 kfree(vm);
737 nvmap_usecount_dec(h);
738 }
739 nvmap_handle_put(h);
740}
741
742struct nvmap_handle_ref *nvmap_alloc(struct nvmap_client *client, size_t size,
743 size_t align, unsigned int flags,
744 unsigned int heap_mask)
745{
746 const unsigned int default_heap = (NVMAP_HEAP_SYSMEM |
747 NVMAP_HEAP_CARVEOUT_GENERIC);
748 struct nvmap_handle_ref *r = NULL;
749 int err;
750
751 if (heap_mask == 0)
752 heap_mask = default_heap;
753
754 r = nvmap_create_handle(client, size);
755 if (IS_ERR(r))
756 return r;
757
758 err = nvmap_alloc_handle_id(client, nvmap_ref_to_id(r),
759 heap_mask, align, flags);
760
761 if (err) {
762 nvmap_free_handle_id(client, nvmap_ref_to_id(r));
763 return ERR_PTR(err);
764 }
765
766 return r;
767}
768
769/* allocates memory with specifed iovm_start address. */
770struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
771 size_t size, size_t align, unsigned int flags, unsigned int iovm_start)
772{
773 int err;
774 struct nvmap_handle *h;
775 struct nvmap_handle_ref *r;
776 const unsigned int default_heap = NVMAP_HEAP_IOVMM;
777
778 /* size need to be more than one page.
779 * otherwise heap preference would change to system heap.
780 */
781 if (size <= PAGE_SIZE)
782 size = PAGE_SIZE << 1;
783 r = nvmap_create_handle(client, size);
784 if (IS_ERR_OR_NULL(r))
785 return r;
786
787 h = r->handle;
788 h->pgalloc.iovm_addr = iovm_start;
789 err = nvmap_alloc_handle_id(client, nvmap_ref_to_id(r),
790 default_heap, align, flags);
791 if (err)
792 goto fail;
793
794 err = mutex_lock_interruptible(&client->share->pin_lock);
795 if (WARN_ON(err))
796 goto fail;
797 err = pin_locked(client, h);
798 mutex_unlock(&client->share->pin_lock);
799 if (err)
800 goto fail;
801 return r;
802
803fail:
804 nvmap_free_handle_id(client, nvmap_ref_to_id(r));
805 return ERR_PTR(err);
806}
807
808void nvmap_free_iovm(struct nvmap_client *client, struct nvmap_handle_ref *r)
809{
810 unsigned long ref_id = nvmap_ref_to_id(r);
811
812 nvmap_unpin_ids(client, 1, &ref_id);
813 nvmap_free_handle_id(client, ref_id);
814}
815
816void nvmap_free(struct nvmap_client *client, struct nvmap_handle_ref *r)
817{
818 if (!r)
819 return;
820
821 nvmap_free_handle_id(client, nvmap_ref_to_id(r));
822}
823
824/*
825 * create a mapping to the user's buffer and write it
826 * (uses similar logic from nvmap_reloc_pin_array to map the cmdbuf)
827 */
828int nvmap_patch_word(struct nvmap_client *client,
829 struct nvmap_handle *patch,
830 u32 patch_offset, u32 patch_value)
831{
832 phys_addr_t phys;
833 unsigned long kaddr;
834 unsigned int pfn;
835 void *addr;
836 pte_t **pte;
837 pgprot_t prot;
838
839 if (patch_offset >= patch->size) {
840 nvmap_warn(client, "read/write outside of handle\n");
841 return -EFAULT;
842 }
843
844 pte = nvmap_alloc_pte(client->dev, &addr);
845 if (IS_ERR(pte))
846 return PTR_ERR(pte);
847
848 /* derive physaddr of cmdbuf WAIT to patch */
849 if (patch->heap_pgalloc) {
850 unsigned int page = patch_offset >> PAGE_SHIFT;
851 phys = page_to_phys(patch->pgalloc.pages[page]);
852 phys += (patch_offset & ~PAGE_MASK);
853 } else {
854 phys = patch->carveout->base + patch_offset;
855 }
856
857 pfn = __phys_to_pfn(phys);
858 prot = nvmap_pgprot(patch, pgprot_kernel);
859 kaddr = (unsigned long)addr;
860
861 /* write PTE, so addr points to cmdbuf PFN */
862 set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, prot));
863 flush_tlb_kernel_page(kaddr);
864
865 /* write patch_value to addr + page offset */
866 __raw_writel(patch_value, addr + (phys & ~PAGE_MASK));
867
868 nvmap_free_pte(client->dev, pte);
869 wmb();
870 return 0;
871}
diff --git a/drivers/video/tegra/nvmap/nvmap.h b/drivers/video/tegra/nvmap/nvmap.h
new file mode 100644
index 00000000000..44a0d86b603
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap.h
@@ -0,0 +1,271 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap.h
3 *
4 * GPU memory management driver for Tegra
5 *
6 * Copyright (c) 2010-2012, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *'
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef __VIDEO_TEGRA_NVMAP_NVMAP_H
24#define __VIDEO_TEGRA_NVMAP_NVMAP_H
25
26#include <linux/list.h>
27#include <linux/mm.h>
28#include <linux/mutex.h>
29#include <linux/rbtree.h>
30#include <linux/sched.h>
31#include <linux/wait.h>
32#include <linux/atomic.h>
33#include <mach/nvmap.h>
34#include "nvmap_heap.h"
35
36struct nvmap_device;
37struct page;
38struct tegra_iovmm_area;
39
40#if defined(CONFIG_TEGRA_NVMAP)
41#define nvmap_err(_client, _fmt, ...) \
42 dev_err(nvmap_client_to_device(_client), \
43 "%s: "_fmt, __func__, ##__VA_ARGS__)
44
45#define nvmap_warn(_client, _fmt, ...) \
46 dev_warn(nvmap_client_to_device(_client), \
47 "%s: "_fmt, __func__, ##__VA_ARGS__)
48
49#define nvmap_debug(_client, _fmt, ...) \
50 dev_dbg(nvmap_client_to_device(_client), \
51 "%s: "_fmt, __func__, ##__VA_ARGS__)
52
53#define nvmap_ref_to_id(_ref) ((unsigned long)(_ref)->handle)
54
55/* handles allocated using shared system memory (either IOVMM- or high-order
56 * page allocations */
57struct nvmap_pgalloc {
58 struct page **pages;
59 struct tegra_iovmm_area *area;
60 struct list_head mru_list; /* MRU entry for IOVMM reclamation */
61 bool contig; /* contiguous system memory */
62 bool dirty; /* area is invalid and needs mapping */
63 u32 iovm_addr; /* is non-zero, if client need specific iova mapping */
64};
65
66struct nvmap_handle {
67 struct rb_node node; /* entry on global handle tree */
68 atomic_t ref; /* reference count (i.e., # of duplications) */
69 atomic_t pin; /* pin count */
70 unsigned int usecount; /* how often is used */
71 unsigned long flags;
72 size_t size; /* padded (as-allocated) size */
73 size_t orig_size; /* original (as-requested) size */
74 size_t align;
75 struct nvmap_client *owner;
76 struct nvmap_device *dev;
77 union {
78 struct nvmap_pgalloc pgalloc;
79 struct nvmap_heap_block *carveout;
80 };
81 bool global; /* handle may be duplicated by other clients */
82 bool secure; /* zap IOVMM area on unpin */
83 bool heap_pgalloc; /* handle is page allocated (sysmem / iovmm) */
84 bool alloc; /* handle has memory allocated */
85 unsigned int userflags; /* flags passed from userspace */
86 struct mutex lock;
87};
88
89#define NVMAP_DEFAULT_PAGE_POOL_SIZE 8192
90#define NVMAP_UC_POOL NVMAP_HANDLE_UNCACHEABLE
91#define NVMAP_WC_POOL NVMAP_HANDLE_WRITE_COMBINE
92#define NVMAP_IWB_POOL NVMAP_HANDLE_INNER_CACHEABLE
93#define NVMAP_WB_POOL NVMAP_HANDLE_CACHEABLE
94#define NVMAP_NUM_POOLS (NVMAP_HANDLE_CACHEABLE + 1)
95
96struct nvmap_page_pool {
97 struct mutex lock;
98 int npages;
99 struct page **page_array;
100 struct page **shrink_array;
101 int max_pages;
102 int flags;
103};
104
105int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags);
106
107struct nvmap_share {
108 struct tegra_iovmm_client *iovmm;
109 wait_queue_head_t pin_wait;
110 struct mutex pin_lock;
111 union {
112 struct nvmap_page_pool pools[NVMAP_NUM_POOLS];
113 struct {
114 struct nvmap_page_pool uc_pool;
115 struct nvmap_page_pool wc_pool;
116 struct nvmap_page_pool iwb_pool;
117 struct nvmap_page_pool wb_pool;
118 };
119 };
120#ifdef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
121 struct mutex mru_lock;
122 struct list_head *mru_lists;
123 int nr_mru;
124#endif
125};
126
127struct nvmap_carveout_commit {
128 size_t commit;
129 struct list_head list;
130};
131
132struct nvmap_client {
133 const char *name;
134 struct nvmap_device *dev;
135 struct nvmap_share *share;
136 struct rb_root handle_refs;
137 atomic_t iovm_commit;
138 size_t iovm_limit;
139 struct mutex ref_lock;
140 bool super;
141 atomic_t count;
142 struct task_struct *task;
143 struct list_head list;
144 struct nvmap_carveout_commit carveout_commit[0];
145};
146
147struct nvmap_vma_priv {
148 struct nvmap_handle *handle;
149 size_t offs;
150 atomic_t count; /* number of processes cloning the VMA */
151};
152
153static inline void nvmap_ref_lock(struct nvmap_client *priv)
154{
155 mutex_lock(&priv->ref_lock);
156}
157
158static inline void nvmap_ref_unlock(struct nvmap_client *priv)
159{
160 mutex_unlock(&priv->ref_lock);
161}
162#endif /* CONFIG_TEGRA_NVMAP */
163
164struct device *nvmap_client_to_device(struct nvmap_client *client);
165
166pte_t **nvmap_alloc_pte(struct nvmap_device *dev, void **vaddr);
167
168pte_t **nvmap_alloc_pte_irq(struct nvmap_device *dev, void **vaddr);
169
170void nvmap_free_pte(struct nvmap_device *dev, pte_t **pte);
171
172void nvmap_usecount_inc(struct nvmap_handle *h);
173void nvmap_usecount_dec(struct nvmap_handle *h);
174
175struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *dev,
176 struct nvmap_handle *handle,
177 unsigned long type);
178
179unsigned long nvmap_carveout_usage(struct nvmap_client *c,
180 struct nvmap_heap_block *b);
181
182struct nvmap_carveout_node;
183void nvmap_carveout_commit_add(struct nvmap_client *client,
184 struct nvmap_carveout_node *node, size_t len);
185
186void nvmap_carveout_commit_subtract(struct nvmap_client *client,
187 struct nvmap_carveout_node *node,
188 size_t len);
189
190struct nvmap_share *nvmap_get_share_from_dev(struct nvmap_device *dev);
191
192struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client,
193 unsigned long handle);
194
195struct nvmap_handle_ref *_nvmap_validate_id_locked(struct nvmap_client *priv,
196 unsigned long id);
197
198struct nvmap_handle *nvmap_get_handle_id(struct nvmap_client *client,
199 unsigned long id);
200
201struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
202 size_t size);
203
204struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
205 unsigned long id);
206
207int nvmap_alloc_handle_id(struct nvmap_client *client,
208 unsigned long id, unsigned int heap_mask,
209 size_t align, unsigned int flags);
210
211void nvmap_free_handle_id(struct nvmap_client *c, unsigned long id);
212
213int nvmap_pin_ids(struct nvmap_client *client,
214 unsigned int nr, const unsigned long *ids);
215
216void nvmap_unpin_ids(struct nvmap_client *priv,
217 unsigned int nr, const unsigned long *ids);
218
219void _nvmap_handle_free(struct nvmap_handle *h);
220
221int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h);
222
223void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h);
224
225#if defined(CONFIG_TEGRA_NVMAP)
226static inline struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h)
227{
228 if (unlikely(atomic_inc_return(&h->ref) <= 1)) {
229 pr_err("%s: %s getting a freed handle\n",
230 __func__, current->group_leader->comm);
231 if (atomic_read(&h->ref) <= 0)
232 return NULL;
233 }
234 return h;
235}
236
237static inline void nvmap_handle_put(struct nvmap_handle *h)
238{
239 int cnt = atomic_dec_return(&h->ref);
240
241 if (WARN_ON(cnt < 0)) {
242 pr_err("%s: %s put to negative references\n",
243 __func__, current->comm);
244 } else if (cnt == 0)
245 _nvmap_handle_free(h);
246}
247
248static inline pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot)
249{
250 if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
251 return pgprot_noncached(prot);
252 else if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
253 return pgprot_writecombine(prot);
254 else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
255 return pgprot_inner_writeback(prot);
256 return prot;
257}
258#else /* CONFIG_TEGRA_NVMAP */
259struct nvmap_handle *nvmap_handle_get(struct nvmap_handle *h);
260void nvmap_handle_put(struct nvmap_handle *h);
261pgprot_t nvmap_pgprot(struct nvmap_handle *h, pgprot_t prot);
262#endif /* !CONFIG_TEGRA_NVMAP */
263
264int is_nvmap_vma(struct vm_area_struct *vma);
265
266struct nvmap_handle_ref *nvmap_alloc_iovm(struct nvmap_client *client,
267 size_t size, size_t align, unsigned int flags, unsigned int iova_start);
268
269void nvmap_free_iovm(struct nvmap_client *client, struct nvmap_handle_ref *r);
270
271#endif
diff --git a/drivers/video/tegra/nvmap/nvmap_common.h b/drivers/video/tegra/nvmap/nvmap_common.h
new file mode 100644
index 00000000000..6da010720bb
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_common.h
@@ -0,0 +1,38 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_common.h
3 *
4 * GPU memory management driver for Tegra
5 *
6 * Copyright (c) 2011, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *'
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23extern void v7_flush_kern_cache_all(void *);
24extern void v7_clean_kern_cache_all(void *);
25
26#define FLUSH_CLEAN_BY_SET_WAY_THRESHOLD (8 * PAGE_SIZE)
27
28static inline void inner_flush_cache_all(void)
29{
30 on_each_cpu(v7_flush_kern_cache_all, NULL, 1);
31}
32
33static inline void inner_clean_cache_all(void)
34{
35 on_each_cpu(v7_clean_kern_cache_all, NULL, 1);
36}
37
38extern void __flush_dcache_page(struct address_space *, struct page *);
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
new file mode 100644
index 00000000000..f84f38c93aa
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -0,0 +1,1436 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_dev.c
3 *
4 * User-space interface to nvmap
5 *
6 * Copyright (c) 2011-2012, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/backing-dev.h>
24#include <linux/bitmap.h>
25#include <linux/debugfs.h>
26#include <linux/delay.h>
27#include <linux/kernel.h>
28#include <linux/miscdevice.h>
29#include <linux/mm.h>
30#include <linux/oom.h>
31#include <linux/platform_device.h>
32#include <linux/seq_file.h>
33#include <linux/slab.h>
34#include <linux/spinlock.h>
35#include <linux/uaccess.h>
36#include <linux/vmalloc.h>
37
38#include <asm/cacheflush.h>
39#include <asm/tlbflush.h>
40
41#include <mach/iovmm.h>
42#include <mach/nvmap.h>
43
44#include "nvmap.h"
45#include "nvmap_ioctl.h"
46#include "nvmap_mru.h"
47#include "nvmap_common.h"
48
49#define NVMAP_NUM_PTES 64
50#define NVMAP_CARVEOUT_KILLER_RETRY_TIME 100 /* msecs */
51
52#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
53static bool carveout_killer = true;
54#else
55static bool carveout_killer;
56#endif
57module_param(carveout_killer, bool, 0640);
58
59struct nvmap_carveout_node {
60 unsigned int heap_bit;
61 struct nvmap_heap *carveout;
62 int index;
63 struct list_head clients;
64 spinlock_t clients_lock;
65};
66
67struct nvmap_device {
68 struct vm_struct *vm_rgn;
69 pte_t *ptes[NVMAP_NUM_PTES];
70 unsigned long ptebits[NVMAP_NUM_PTES / BITS_PER_LONG];
71 unsigned int lastpte;
72 spinlock_t ptelock;
73
74 struct rb_root handles;
75 spinlock_t handle_lock;
76 wait_queue_head_t pte_wait;
77 struct miscdevice dev_super;
78 struct miscdevice dev_user;
79 struct nvmap_carveout_node *heaps;
80 int nr_carveouts;
81 struct nvmap_share iovmm_master;
82 struct list_head clients;
83 spinlock_t clients_lock;
84};
85
86struct nvmap_device *nvmap_dev;
87
88static struct backing_dev_info nvmap_bdi = {
89 .ra_pages = 0,
90 .capabilities = (BDI_CAP_NO_ACCT_AND_WRITEBACK |
91 BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP),
92};
93
94static int nvmap_open(struct inode *inode, struct file *filp);
95static int nvmap_release(struct inode *inode, struct file *filp);
96static long nvmap_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
97static int nvmap_map(struct file *filp, struct vm_area_struct *vma);
98static void nvmap_vma_open(struct vm_area_struct *vma);
99static void nvmap_vma_close(struct vm_area_struct *vma);
100static int nvmap_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
101
102static const struct file_operations nvmap_user_fops = {
103 .owner = THIS_MODULE,
104 .open = nvmap_open,
105 .release = nvmap_release,
106 .unlocked_ioctl = nvmap_ioctl,
107 .mmap = nvmap_map,
108};
109
110static const struct file_operations nvmap_super_fops = {
111 .owner = THIS_MODULE,
112 .open = nvmap_open,
113 .release = nvmap_release,
114 .unlocked_ioctl = nvmap_ioctl,
115 .mmap = nvmap_map,
116};
117
118static struct vm_operations_struct nvmap_vma_ops = {
119 .open = nvmap_vma_open,
120 .close = nvmap_vma_close,
121 .fault = nvmap_vma_fault,
122};
123
124int is_nvmap_vma(struct vm_area_struct *vma)
125{
126 return vma->vm_ops == &nvmap_vma_ops;
127}
128
129struct device *nvmap_client_to_device(struct nvmap_client *client)
130{
131 if (client->super)
132 return client->dev->dev_super.this_device;
133 else
134 return client->dev->dev_user.this_device;
135}
136
137struct nvmap_share *nvmap_get_share_from_dev(struct nvmap_device *dev)
138{
139 return &dev->iovmm_master;
140}
141
142/* allocates a PTE for the caller's use; returns the PTE pointer or
143 * a negative errno. may be called from IRQs */
144pte_t **nvmap_alloc_pte_irq(struct nvmap_device *dev, void **vaddr)
145{
146 unsigned long flags;
147 unsigned long bit;
148
149 spin_lock_irqsave(&dev->ptelock, flags);
150 bit = find_next_zero_bit(dev->ptebits, NVMAP_NUM_PTES, dev->lastpte);
151 if (bit == NVMAP_NUM_PTES) {
152 bit = find_first_zero_bit(dev->ptebits, dev->lastpte);
153 if (bit == dev->lastpte)
154 bit = NVMAP_NUM_PTES;
155 }
156
157 if (bit == NVMAP_NUM_PTES) {
158 spin_unlock_irqrestore(&dev->ptelock, flags);
159 return ERR_PTR(-ENOMEM);
160 }
161
162 dev->lastpte = bit;
163 set_bit(bit, dev->ptebits);
164 spin_unlock_irqrestore(&dev->ptelock, flags);
165
166 *vaddr = dev->vm_rgn->addr + bit * PAGE_SIZE;
167 return &(dev->ptes[bit]);
168}
169
170/* allocates a PTE for the caller's use; returns the PTE pointer or
171 * a negative errno. must be called from sleepable contexts */
172pte_t **nvmap_alloc_pte(struct nvmap_device *dev, void **vaddr)
173{
174 int ret;
175 pte_t **pte;
176 ret = wait_event_interruptible(dev->pte_wait,
177 !IS_ERR(pte = nvmap_alloc_pte_irq(dev, vaddr)));
178
179 if (ret == -ERESTARTSYS)
180 return ERR_PTR(-EINTR);
181
182 return pte;
183}
184
185/* frees a PTE */
186void nvmap_free_pte(struct nvmap_device *dev, pte_t **pte)
187{
188 unsigned long addr;
189 unsigned int bit = pte - dev->ptes;
190 unsigned long flags;
191
192 if (WARN_ON(bit >= NVMAP_NUM_PTES))
193 return;
194
195 addr = (unsigned long)dev->vm_rgn->addr + bit * PAGE_SIZE;
196 set_pte_at(&init_mm, addr, *pte, 0);
197
198 spin_lock_irqsave(&dev->ptelock, flags);
199 clear_bit(bit, dev->ptebits);
200 spin_unlock_irqrestore(&dev->ptelock, flags);
201 wake_up(&dev->pte_wait);
202}
203
204/* verifies that the handle ref value "ref" is a valid handle ref for the
205 * file. caller must hold the file's ref_lock prior to calling this function */
206struct nvmap_handle_ref *_nvmap_validate_id_locked(struct nvmap_client *c,
207 unsigned long id)
208{
209 struct rb_node *n = c->handle_refs.rb_node;
210
211 while (n) {
212 struct nvmap_handle_ref *ref;
213 ref = rb_entry(n, struct nvmap_handle_ref, node);
214 if ((unsigned long)ref->handle == id)
215 return ref;
216 else if (id > (unsigned long)ref->handle)
217 n = n->rb_right;
218 else
219 n = n->rb_left;
220 }
221
222 return NULL;
223}
224
225struct nvmap_handle *nvmap_get_handle_id(struct nvmap_client *client,
226 unsigned long id)
227{
228 struct nvmap_handle_ref *ref;
229 struct nvmap_handle *h = NULL;
230
231 nvmap_ref_lock(client);
232 ref = _nvmap_validate_id_locked(client, id);
233 if (ref)
234 h = ref->handle;
235 if (h)
236 h = nvmap_handle_get(h);
237 nvmap_ref_unlock(client);
238 return h;
239}
240
241unsigned long nvmap_carveout_usage(struct nvmap_client *c,
242 struct nvmap_heap_block *b)
243{
244 struct nvmap_heap *h = nvmap_block_to_heap(b);
245 struct nvmap_carveout_node *n;
246 int i;
247
248 for (i = 0; i < c->dev->nr_carveouts; i++) {
249 n = &c->dev->heaps[i];
250 if (n->carveout == h)
251 return n->heap_bit;
252 }
253 return 0;
254}
255
256/*
257 * This routine is used to flush the carveout memory from cache.
258 * Why cache flush is needed for carveout? Consider the case, where a piece of
259 * carveout is allocated as cached and released. After this, if the same memory is
260 * allocated for uncached request and the memory is not flushed out from cache.
261 * In this case, the client might pass this to H/W engine and it could start modify
262 * the memory. As this was cached earlier, it might have some portion of it in cache.
263 * During cpu request to read/write other memory, the cached portion of this memory
264 * might get flushed back to main memory and would cause corruptions, if it happens
265 * after H/W writes data to memory.
266 *
267 * But flushing out the memory blindly on each carveout allocation is redundant.
268 *
269 * In order to optimize the carveout buffer cache flushes, the following
270 * strategy is used.
271 *
272 * The whole Carveout is flushed out from cache during its initialization.
273 * During allocation, carveout buffers are not flused from cache.
274 * During deallocation, carveout buffers are flushed, if they were allocated as cached.
275 * if they were allocated as uncached/writecombined, no cache flush is needed.
276 * Just draining store buffers is enough.
277 */
278int nvmap_flush_heap_block(struct nvmap_client *client,
279 struct nvmap_heap_block *block, size_t len, unsigned int prot)
280{
281 pte_t **pte;
282 void *addr;
283 phys_addr_t kaddr;
284 phys_addr_t phys = block->base;
285 phys_addr_t end = block->base + len;
286
287 if (prot == NVMAP_HANDLE_UNCACHEABLE || prot == NVMAP_HANDLE_WRITE_COMBINE)
288 goto out;
289
290 if (len >= FLUSH_CLEAN_BY_SET_WAY_THRESHOLD) {
291 inner_flush_cache_all();
292 if (prot != NVMAP_HANDLE_INNER_CACHEABLE)
293 outer_flush_range(block->base, block->base + len);
294 goto out;
295 }
296
297 pte = nvmap_alloc_pte((client ? client->dev : nvmap_dev), &addr);
298 if (IS_ERR(pte))
299 return PTR_ERR(pte);
300
301 kaddr = (phys_addr_t)addr;
302
303 while (phys < end) {
304 phys_addr_t next = (phys + PAGE_SIZE) & PAGE_MASK;
305 unsigned long pfn = __phys_to_pfn(phys);
306 void *base = (void *)kaddr + (phys & ~PAGE_MASK);
307
308 next = min(next, end);
309 set_pte_at(&init_mm, kaddr, *pte, pfn_pte(pfn, pgprot_kernel));
310 flush_tlb_kernel_page(kaddr);
311 __cpuc_flush_dcache_area(base, next - phys);
312 phys = next;
313 }
314
315 if (prot != NVMAP_HANDLE_INNER_CACHEABLE)
316 outer_flush_range(block->base, block->base + len);
317
318 nvmap_free_pte((client ? client->dev : nvmap_dev), pte);
319out:
320 wmb();
321 return 0;
322}
323
324void nvmap_carveout_commit_add(struct nvmap_client *client,
325 struct nvmap_carveout_node *node,
326 size_t len)
327{
328 unsigned long flags;
329
330 nvmap_ref_lock(client);
331 spin_lock_irqsave(&node->clients_lock, flags);
332 BUG_ON(list_empty(&client->carveout_commit[node->index].list) &&
333 client->carveout_commit[node->index].commit != 0);
334
335 client->carveout_commit[node->index].commit += len;
336 /* if this client isn't already on the list of nodes for this heap,
337 add it */
338 if (list_empty(&client->carveout_commit[node->index].list)) {
339 list_add(&client->carveout_commit[node->index].list,
340 &node->clients);
341 }
342 spin_unlock_irqrestore(&node->clients_lock, flags);
343 nvmap_ref_unlock(client);
344}
345
346void nvmap_carveout_commit_subtract(struct nvmap_client *client,
347 struct nvmap_carveout_node *node,
348 size_t len)
349{
350 unsigned long flags;
351
352 if (!client)
353 return;
354
355 spin_lock_irqsave(&node->clients_lock, flags);
356 BUG_ON(client->carveout_commit[node->index].commit < len);
357 client->carveout_commit[node->index].commit -= len;
358 /* if no more allocation in this carveout for this node, delete it */
359 if (!client->carveout_commit[node->index].commit)
360 list_del_init(&client->carveout_commit[node->index].list);
361 spin_unlock_irqrestore(&node->clients_lock, flags);
362}
363
364static struct nvmap_client *get_client_from_carveout_commit(
365 struct nvmap_carveout_node *node, struct nvmap_carveout_commit *commit)
366{
367 struct nvmap_carveout_commit *first_commit = commit - node->index;
368 return (void *)first_commit - offsetof(struct nvmap_client,
369 carveout_commit);
370}
371
372static DECLARE_WAIT_QUEUE_HEAD(wait_reclaim);
373static int wait_count;
374bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
375{
376 struct nvmap_carveout_commit *commit;
377 size_t selected_size = 0;
378 int selected_oom_adj = OOM_ADJUST_MIN;
379 struct task_struct *selected_task = NULL;
380 unsigned long flags;
381 bool wait = false;
382 int current_oom_adj = OOM_ADJUST_MIN;
383
384 task_lock(current);
385 if (current->signal)
386 current_oom_adj = current->signal->oom_adj;
387 task_unlock(current);
388
389 spin_lock_irqsave(&node->clients_lock, flags);
390 /* find the task with the smallest oom_adj (lowest priority)
391 * and largest carveout allocation -- ignore kernel allocations,
392 * there's no way to handle them */
393 list_for_each_entry(commit, &node->clients, list) {
394 struct nvmap_client *client =
395 get_client_from_carveout_commit(node, commit);
396 size_t size = commit->commit;
397 struct task_struct *task = client->task;
398 struct signal_struct *sig;
399
400 if (!task)
401 continue;
402
403 task_lock(task);
404 sig = task->signal;
405 if (!task->mm || !sig)
406 goto end;
407 /* don't try to kill current */
408 if (task == current->group_leader)
409 goto end;
410 /* don't try to kill higher priority tasks */
411 if (sig->oom_adj < current_oom_adj)
412 goto end;
413 if (sig->oom_adj < selected_oom_adj)
414 goto end;
415 if (sig->oom_adj == selected_oom_adj &&
416 size <= selected_size)
417 goto end;
418 selected_oom_adj = sig->oom_adj;
419 selected_size = size;
420 selected_task = task;
421end:
422 task_unlock(task);
423 }
424 if (selected_task) {
425 wait = true;
426 if (fatal_signal_pending(selected_task)) {
427 pr_warning("carveout_killer: process %d dying "
428 "slowly\n", selected_task->pid);
429 goto out;
430 }
431 pr_info("carveout_killer: killing process %d with oom_adj %d "
432 "to reclaim %d (for process with oom_adj %d)\n",
433 selected_task->pid, selected_oom_adj,
434 selected_size, current_oom_adj);
435 force_sig(SIGKILL, selected_task);
436 }
437out:
438 spin_unlock_irqrestore(&node->clients_lock, flags);
439 return wait;
440}
441
442static
443struct nvmap_heap_block *do_nvmap_carveout_alloc(struct nvmap_client *client,
444 struct nvmap_handle *handle,
445 unsigned long type)
446{
447 struct nvmap_carveout_node *co_heap;
448 struct nvmap_device *dev = client->dev;
449 int i;
450
451 for (i = 0; i < dev->nr_carveouts; i++) {
452 struct nvmap_heap_block *block;
453 co_heap = &dev->heaps[i];
454
455 if (!(co_heap->heap_bit & type))
456 continue;
457
458 block = nvmap_heap_alloc(co_heap->carveout, handle);
459 if (block)
460 return block;
461 }
462 return NULL;
463}
464
465static bool nvmap_carveout_freed(int count)
466{
467 smp_rmb();
468 return count != wait_count;
469}
470
471struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
472 struct nvmap_handle *handle,
473 unsigned long type)
474{
475 struct nvmap_heap_block *block;
476 struct nvmap_carveout_node *co_heap;
477 struct nvmap_device *dev = client->dev;
478 int i;
479 unsigned long end = jiffies +
480 msecs_to_jiffies(NVMAP_CARVEOUT_KILLER_RETRY_TIME);
481 int count = 0;
482
483 do {
484 block = do_nvmap_carveout_alloc(client, handle, type);
485 if (!carveout_killer)
486 return block;
487
488 if (block)
489 return block;
490
491 if (!count++) {
492 char task_comm[TASK_COMM_LEN];
493 if (client->task)
494 get_task_comm(task_comm, client->task);
495 else
496 task_comm[0] = 0;
497 pr_info("%s: failed to allocate %u bytes for "
498 "process %s, firing carveout "
499 "killer!\n", __func__, handle->size, task_comm);
500
501 } else {
502 pr_info("%s: still can't allocate %u bytes, "
503 "attempt %d!\n", __func__, handle->size, count);
504 }
505
506 /* shrink carveouts that matter and try again */
507 for (i = 0; i < dev->nr_carveouts; i++) {
508 int count;
509 co_heap = &dev->heaps[i];
510
511 if (!(co_heap->heap_bit & type))
512 continue;
513
514 count = wait_count;
515 /* indicates we didn't find anything to kill,
516 might as well stop trying */
517 if (!nvmap_shrink_carveout(co_heap))
518 return NULL;
519
520 if (time_is_after_jiffies(end))
521 wait_event_interruptible_timeout(wait_reclaim,
522 nvmap_carveout_freed(count),
523 end - jiffies);
524 }
525 } while (time_is_after_jiffies(end));
526
527 if (time_is_before_jiffies(end))
528 pr_info("carveout_killer: timeout expired without "
529 "allocation succeeding.\n");
530
531 return NULL;
532}
533
534/* remove a handle from the device's tree of all handles; called
535 * when freeing handles. */
536int nvmap_handle_remove(struct nvmap_device *dev, struct nvmap_handle *h)
537{
538 spin_lock(&dev->handle_lock);
539
540 /* re-test inside the spinlock if the handle really has no clients;
541 * only remove the handle if it is unreferenced */
542 if (atomic_add_return(0, &h->ref) > 0) {
543 spin_unlock(&dev->handle_lock);
544 return -EBUSY;
545 }
546 smp_rmb();
547 BUG_ON(atomic_read(&h->ref) < 0);
548 BUG_ON(atomic_read(&h->pin) != 0);
549
550 rb_erase(&h->node, &dev->handles);
551
552 spin_unlock(&dev->handle_lock);
553 return 0;
554}
555
556/* adds a newly-created handle to the device master tree */
557void nvmap_handle_add(struct nvmap_device *dev, struct nvmap_handle *h)
558{
559 struct rb_node **p;
560 struct rb_node *parent = NULL;
561
562 spin_lock(&dev->handle_lock);
563 p = &dev->handles.rb_node;
564 while (*p) {
565 struct nvmap_handle *b;
566
567 parent = *p;
568 b = rb_entry(parent, struct nvmap_handle, node);
569 if (h > b)
570 p = &parent->rb_right;
571 else
572 p = &parent->rb_left;
573 }
574 rb_link_node(&h->node, parent, p);
575 rb_insert_color(&h->node, &dev->handles);
576 spin_unlock(&dev->handle_lock);
577}
578
579/* validates that a handle is in the device master tree, and that the
580 * client has permission to access it */
581struct nvmap_handle *nvmap_validate_get(struct nvmap_client *client,
582 unsigned long id)
583{
584 struct nvmap_handle *h = NULL;
585 struct rb_node *n;
586
587 spin_lock(&client->dev->handle_lock);
588
589 n = client->dev->handles.rb_node;
590
591 while (n) {
592 h = rb_entry(n, struct nvmap_handle, node);
593 if ((unsigned long)h == id) {
594 if (client->super || h->global || (h->owner == client))
595 h = nvmap_handle_get(h);
596 else
597 h = NULL;
598 spin_unlock(&client->dev->handle_lock);
599 return h;
600 }
601 if (id > (unsigned long)h)
602 n = n->rb_right;
603 else
604 n = n->rb_left;
605 }
606 spin_unlock(&client->dev->handle_lock);
607 return NULL;
608}
609
610struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
611 const char *name)
612{
613 struct nvmap_client *client;
614 struct task_struct *task;
615 int i;
616
617 if (WARN_ON(!dev))
618 return NULL;
619
620 client = kzalloc(sizeof(*client) + (sizeof(struct nvmap_carveout_commit)
621 * dev->nr_carveouts), GFP_KERNEL);
622 if (!client)
623 return NULL;
624
625 client->name = name;
626 client->super = true;
627 client->dev = dev;
628 /* TODO: allocate unique IOVMM client for each nvmap client */
629 client->share = &dev->iovmm_master;
630 client->handle_refs = RB_ROOT;
631
632 atomic_set(&client->iovm_commit, 0);
633
634 client->iovm_limit = nvmap_mru_vm_size(client->share->iovmm);
635
636 for (i = 0; i < dev->nr_carveouts; i++) {
637 INIT_LIST_HEAD(&client->carveout_commit[i].list);
638 client->carveout_commit[i].commit = 0;
639 }
640
641 get_task_struct(current->group_leader);
642 task_lock(current->group_leader);
643 /* don't bother to store task struct for kernel threads,
644 they can't be killed anyway */
645 if (current->flags & PF_KTHREAD) {
646 put_task_struct(current->group_leader);
647 task = NULL;
648 } else {
649 task = current->group_leader;
650 }
651 task_unlock(current->group_leader);
652 client->task = task;
653
654 mutex_init(&client->ref_lock);
655 atomic_set(&client->count, 1);
656
657 spin_lock(&dev->clients_lock);
658 list_add(&client->list, &dev->clients);
659 spin_unlock(&dev->clients_lock);
660 return client;
661}
662
663static void destroy_client(struct nvmap_client *client)
664{
665 struct rb_node *n;
666 int i;
667
668 if (!client)
669 return;
670
671
672 while ((n = rb_first(&client->handle_refs))) {
673 struct nvmap_handle_ref *ref;
674 int pins, dupes;
675
676 ref = rb_entry(n, struct nvmap_handle_ref, node);
677 rb_erase(&ref->node, &client->handle_refs);
678
679 smp_rmb();
680 pins = atomic_read(&ref->pin);
681
682 if (ref->handle->owner == client)
683 ref->handle->owner = NULL;
684
685 while (pins--)
686 nvmap_unpin_handles(client, &ref->handle, 1);
687
688 dupes = atomic_read(&ref->dupes);
689 while (dupes--)
690 nvmap_handle_put(ref->handle);
691
692 kfree(ref);
693 }
694
695 if (carveout_killer) {
696 wait_count++;
697 smp_wmb();
698 wake_up_all(&wait_reclaim);
699 }
700
701 for (i = 0; i < client->dev->nr_carveouts; i++)
702 list_del(&client->carveout_commit[i].list);
703
704 if (client->task)
705 put_task_struct(client->task);
706
707 spin_lock(&client->dev->clients_lock);
708 list_del(&client->list);
709 spin_unlock(&client->dev->clients_lock);
710 kfree(client);
711}
712
713struct nvmap_client *nvmap_client_get(struct nvmap_client *client)
714{
715 if (WARN_ON(!client))
716 return NULL;
717
718 if (WARN_ON(!atomic_add_unless(&client->count, 1, 0)))
719 return NULL;
720
721 return client;
722}
723
724struct nvmap_client *nvmap_client_get_file(int fd)
725{
726 struct nvmap_client *client = ERR_PTR(-EFAULT);
727 struct file *f = fget(fd);
728 if (!f)
729 return ERR_PTR(-EINVAL);
730
731 if ((f->f_op == &nvmap_user_fops) || (f->f_op == &nvmap_super_fops)) {
732 client = f->private_data;
733 atomic_inc(&client->count);
734 }
735
736 fput(f);
737 return client;
738}
739
740void nvmap_client_put(struct nvmap_client *client)
741{
742 if (!client)
743 return;
744
745 if (!atomic_dec_return(&client->count))
746 destroy_client(client);
747}
748
749static int nvmap_open(struct inode *inode, struct file *filp)
750{
751 struct miscdevice *miscdev = filp->private_data;
752 struct nvmap_device *dev = dev_get_drvdata(miscdev->parent);
753 struct nvmap_client *priv;
754 int ret;
755
756 ret = nonseekable_open(inode, filp);
757 if (unlikely(ret))
758 return ret;
759
760 BUG_ON(dev != nvmap_dev);
761 priv = nvmap_create_client(dev, "user");
762 if (!priv)
763 return -ENOMEM;
764
765 priv->super = (filp->f_op == &nvmap_super_fops);
766
767 filp->f_mapping->backing_dev_info = &nvmap_bdi;
768
769 filp->private_data = priv;
770 return 0;
771}
772
773static int nvmap_release(struct inode *inode, struct file *filp)
774{
775 nvmap_client_put(filp->private_data);
776 return 0;
777}
778
779static int nvmap_map(struct file *filp, struct vm_area_struct *vma)
780{
781 struct nvmap_vma_priv *priv;
782
783 /* after NVMAP_IOC_MMAP, the handle that is mapped by this VMA
784 * will be stored in vm_private_data and faulted in. until the
785 * ioctl is made, the VMA is mapped no-access */
786 vma->vm_private_data = NULL;
787
788 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
789 if (!priv)
790 return -ENOMEM;
791
792 priv->offs = 0;
793 priv->handle = NULL;
794 atomic_set(&priv->count, 1);
795
796 vma->vm_flags |= VM_SHARED;
797 vma->vm_flags |= (VM_IO | VM_DONTEXPAND | VM_MIXEDMAP | VM_RESERVED);
798 vma->vm_ops = &nvmap_vma_ops;
799 vma->vm_private_data = priv;
800
801 return 0;
802}
803
804static long nvmap_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
805{
806 int err = 0;
807 void __user *uarg = (void __user *)arg;
808
809 if (_IOC_TYPE(cmd) != NVMAP_IOC_MAGIC)
810 return -ENOTTY;
811
812 if (_IOC_NR(cmd) > NVMAP_IOC_MAXNR)
813 return -ENOTTY;
814
815 if (_IOC_DIR(cmd) & _IOC_READ)
816 err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
817 if (_IOC_DIR(cmd) & _IOC_WRITE)
818 err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
819
820 if (err)
821 return -EFAULT;
822
823 switch (cmd) {
824 case NVMAP_IOC_CLAIM:
825 nvmap_warn(filp->private_data, "preserved handles not"
826 "supported\n");
827 err = -ENODEV;
828 break;
829 case NVMAP_IOC_CREATE:
830 case NVMAP_IOC_FROM_ID:
831 err = nvmap_ioctl_create(filp, cmd, uarg);
832 break;
833
834 case NVMAP_IOC_GET_ID:
835 err = nvmap_ioctl_getid(filp, uarg);
836 break;
837
838 case NVMAP_IOC_PARAM:
839 err = nvmap_ioctl_get_param(filp, uarg);
840 break;
841
842 case NVMAP_IOC_UNPIN_MULT:
843 case NVMAP_IOC_PIN_MULT:
844 err = nvmap_ioctl_pinop(filp, cmd == NVMAP_IOC_PIN_MULT, uarg);
845 break;
846
847 case NVMAP_IOC_ALLOC:
848 err = nvmap_ioctl_alloc(filp, uarg);
849 break;
850
851 case NVMAP_IOC_FREE:
852 err = nvmap_ioctl_free(filp, arg);
853 break;
854
855 case NVMAP_IOC_MMAP:
856 err = nvmap_map_into_caller_ptr(filp, uarg);
857 break;
858
859 case NVMAP_IOC_WRITE:
860 case NVMAP_IOC_READ:
861 err = nvmap_ioctl_rw_handle(filp, cmd == NVMAP_IOC_READ, uarg);
862 break;
863
864 case NVMAP_IOC_CACHE:
865 err = nvmap_ioctl_cache_maint(filp, uarg);
866 break;
867
868 default:
869 return -ENOTTY;
870 }
871 return err;
872}
873
874/* to ensure that the backing store for the VMA isn't freed while a fork'd
875 * reference still exists, nvmap_vma_open increments the reference count on
876 * the handle, and nvmap_vma_close decrements it. alternatively, we could
877 * disallow copying of the vma, or behave like pmem and zap the pages. FIXME.
878*/
879static void nvmap_vma_open(struct vm_area_struct *vma)
880{
881 struct nvmap_vma_priv *priv;
882
883 priv = vma->vm_private_data;
884
885 BUG_ON(!priv);
886
887 atomic_inc(&priv->count);
888}
889
890static void nvmap_vma_close(struct vm_area_struct *vma)
891{
892 struct nvmap_vma_priv *priv = vma->vm_private_data;
893
894 if (priv) {
895 if (priv->handle) {
896 nvmap_usecount_dec(priv->handle);
897 BUG_ON(priv->handle->usecount < 0);
898 }
899 if (!atomic_dec_return(&priv->count)) {
900 if (priv->handle)
901 nvmap_handle_put(priv->handle);
902 kfree(priv);
903 }
904 }
905 vma->vm_private_data = NULL;
906}
907
908static int nvmap_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
909{
910 struct nvmap_vma_priv *priv;
911 unsigned long offs;
912
913 offs = (unsigned long)(vmf->virtual_address - vma->vm_start);
914 priv = vma->vm_private_data;
915 if (!priv || !priv->handle || !priv->handle->alloc)
916 return VM_FAULT_SIGBUS;
917
918 offs += priv->offs;
919 /* if the VMA was split for some reason, vm_pgoff will be the VMA's
920 * offset from the original VMA */
921 offs += (vma->vm_pgoff << PAGE_SHIFT);
922
923 if (offs >= priv->handle->size)
924 return VM_FAULT_SIGBUS;
925
926 if (!priv->handle->heap_pgalloc) {
927 unsigned long pfn;
928 BUG_ON(priv->handle->carveout->base & ~PAGE_MASK);
929 pfn = ((priv->handle->carveout->base + offs) >> PAGE_SHIFT);
930 vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
931 return VM_FAULT_NOPAGE;
932 } else {
933 struct page *page;
934 offs >>= PAGE_SHIFT;
935 page = priv->handle->pgalloc.pages[offs];
936 if (page)
937 get_page(page);
938 vmf->page = page;
939 return (page) ? 0 : VM_FAULT_SIGBUS;
940 }
941}
942
943static ssize_t attr_show_usage(struct device *dev,
944 struct device_attribute *attr, char *buf)
945{
946 struct nvmap_carveout_node *node = nvmap_heap_device_to_arg(dev);
947
948 return sprintf(buf, "%08x\n", node->heap_bit);
949}
950
951static struct device_attribute heap_attr_show_usage =
952 __ATTR(usage, S_IRUGO, attr_show_usage, NULL);
953
954static struct attribute *heap_extra_attrs[] = {
955 &heap_attr_show_usage.attr,
956 NULL,
957};
958
959static struct attribute_group heap_extra_attr_group = {
960 .attrs = heap_extra_attrs,
961};
962
963static void client_stringify(struct nvmap_client *client, struct seq_file *s)
964{
965 char task_comm[TASK_COMM_LEN];
966 if (!client->task) {
967 seq_printf(s, "%-18s %18s %8u", client->name, "kernel", 0);
968 return;
969 }
970 get_task_comm(task_comm, client->task);
971 seq_printf(s, "%-18s %18s %8u", client->name, task_comm,
972 client->task->pid);
973}
974
975static void allocations_stringify(struct nvmap_client *client,
976 struct seq_file *s)
977{
978 unsigned long base = 0;
979 struct rb_node *n = rb_first(&client->handle_refs);
980
981 for (; n != NULL; n = rb_next(n)) {
982 struct nvmap_handle_ref *ref =
983 rb_entry(n, struct nvmap_handle_ref, node);
984 struct nvmap_handle *handle = ref->handle;
985 if (handle->alloc && !handle->heap_pgalloc) {
986 seq_printf(s, "%-18s %-18s %8lx %10u %8x\n", "", "",
987 (unsigned long)(handle->carveout->base),
988 handle->size, handle->userflags);
989 } else if (handle->alloc && handle->heap_pgalloc) {
990 seq_printf(s, "%-18s %-18s %8lx %10u %8x\n", "", "",
991 base, handle->size, handle->userflags);
992 }
993 }
994}
995
996static int nvmap_debug_allocations_show(struct seq_file *s, void *unused)
997{
998 struct nvmap_carveout_node *node = s->private;
999 struct nvmap_carveout_commit *commit;
1000 unsigned long flags;
1001 unsigned int total = 0;
1002
1003 spin_lock_irqsave(&node->clients_lock, flags);
1004 seq_printf(s, "%-18s %18s %8s %10s %8s\n", "CLIENT", "PROCESS", "PID",
1005 "SIZE", "FLAGS");
1006 seq_printf(s, "%-18s %18s %8s %10s\n", "", "",
1007 "BASE", "SIZE");
1008 list_for_each_entry(commit, &node->clients, list) {
1009 struct nvmap_client *client =
1010 get_client_from_carveout_commit(node, commit);
1011 client_stringify(client, s);
1012 seq_printf(s, " %10u\n", commit->commit);
1013 allocations_stringify(client, s);
1014 seq_printf(s, "\n");
1015 total += commit->commit;
1016 }
1017 seq_printf(s, "%-18s %-18s %8u %10u\n", "total", "", 0, total);
1018 spin_unlock_irqrestore(&node->clients_lock, flags);
1019
1020 return 0;
1021}
1022
1023static int nvmap_debug_allocations_open(struct inode *inode, struct file *file)
1024{
1025 return single_open(file, nvmap_debug_allocations_show,
1026 inode->i_private);
1027}
1028
1029static const struct file_operations debug_allocations_fops = {
1030 .open = nvmap_debug_allocations_open,
1031 .read = seq_read,
1032 .llseek = seq_lseek,
1033 .release = single_release,
1034};
1035
1036static int nvmap_debug_clients_show(struct seq_file *s, void *unused)
1037{
1038 struct nvmap_carveout_node *node = s->private;
1039 struct nvmap_carveout_commit *commit;
1040 unsigned long flags;
1041 unsigned int total = 0;
1042
1043 spin_lock_irqsave(&node->clients_lock, flags);
1044 seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
1045 "SIZE");
1046 list_for_each_entry(commit, &node->clients, list) {
1047 struct nvmap_client *client =
1048 get_client_from_carveout_commit(node, commit);
1049 client_stringify(client, s);
1050 seq_printf(s, " %10u\n", commit->commit);
1051 total += commit->commit;
1052 }
1053 seq_printf(s, "%-18s %18s %8u %10u\n", "total", "", 0, total);
1054 spin_unlock_irqrestore(&node->clients_lock, flags);
1055
1056 return 0;
1057}
1058
1059static int nvmap_debug_clients_open(struct inode *inode, struct file *file)
1060{
1061 return single_open(file, nvmap_debug_clients_show, inode->i_private);
1062}
1063
1064static const struct file_operations debug_clients_fops = {
1065 .open = nvmap_debug_clients_open,
1066 .read = seq_read,
1067 .llseek = seq_lseek,
1068 .release = single_release,
1069};
1070
1071static int nvmap_debug_iovmm_clients_show(struct seq_file *s, void *unused)
1072{
1073 unsigned long flags;
1074 unsigned int total = 0;
1075 struct nvmap_client *client;
1076 struct nvmap_device *dev = s->private;
1077
1078 spin_lock_irqsave(&dev->clients_lock, flags);
1079 seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
1080 "SIZE");
1081 list_for_each_entry(client, &dev->clients, list) {
1082 client_stringify(client, s);
1083 seq_printf(s, " %10u\n", atomic_read(&client->iovm_commit));
1084 total += atomic_read(&client->iovm_commit);
1085 }
1086 seq_printf(s, "%-18s %18s %8u %10u\n", "total", "", 0, total);
1087 spin_unlock_irqrestore(&dev->clients_lock, flags);
1088
1089 return 0;
1090}
1091
1092static int nvmap_debug_iovmm_clients_open(struct inode *inode,
1093 struct file *file)
1094{
1095 return single_open(file, nvmap_debug_iovmm_clients_show,
1096 inode->i_private);
1097}
1098
1099static const struct file_operations debug_iovmm_clients_fops = {
1100 .open = nvmap_debug_iovmm_clients_open,
1101 .read = seq_read,
1102 .llseek = seq_lseek,
1103 .release = single_release,
1104};
1105
1106static int nvmap_debug_iovmm_allocations_show(struct seq_file *s, void *unused)
1107{
1108 unsigned long flags;
1109 unsigned int total = 0;
1110 struct nvmap_client *client;
1111 struct nvmap_device *dev = s->private;
1112
1113 spin_lock_irqsave(&dev->clients_lock, flags);
1114 seq_printf(s, "%-18s %18s %8s %10s\n", "CLIENT", "PROCESS", "PID",
1115 "SIZE");
1116 seq_printf(s, "%-18s %18s %8s %10s\n", "", "",
1117 "BASE", "SIZE");
1118 list_for_each_entry(client, &dev->clients, list) {
1119 client_stringify(client, s);
1120 seq_printf(s, " %10u\n", atomic_read(&client->iovm_commit));
1121 allocations_stringify(client, s);
1122 seq_printf(s, "\n");
1123 total += atomic_read(&client->iovm_commit);
1124 }
1125 seq_printf(s, "%-18s %-18s %8u %10u\n", "total", "", 0, total);
1126 spin_unlock_irqrestore(&dev->clients_lock, flags);
1127
1128 return 0;
1129}
1130
1131static int nvmap_debug_iovmm_allocations_open(struct inode *inode,
1132 struct file *file)
1133{
1134 return single_open(file, nvmap_debug_iovmm_allocations_show,
1135 inode->i_private);
1136}
1137
1138static const struct file_operations debug_iovmm_allocations_fops = {
1139 .open = nvmap_debug_iovmm_allocations_open,
1140 .read = seq_read,
1141 .llseek = seq_lseek,
1142 .release = single_release,
1143};
1144
1145static int nvmap_probe(struct platform_device *pdev)
1146{
1147 struct nvmap_platform_data *plat = pdev->dev.platform_data;
1148 struct nvmap_device *dev;
1149 struct dentry *nvmap_debug_root;
1150 unsigned int i;
1151 int e;
1152
1153 if (!plat) {
1154 dev_err(&pdev->dev, "no platform data?\n");
1155 return -ENODEV;
1156 }
1157
1158 if (WARN_ON(nvmap_dev != NULL)) {
1159 dev_err(&pdev->dev, "only one nvmap device may be present\n");
1160 return -ENODEV;
1161 }
1162
1163 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1164 if (!dev) {
1165 dev_err(&pdev->dev, "out of memory for device\n");
1166 return -ENOMEM;
1167 }
1168
1169 dev->dev_user.minor = MISC_DYNAMIC_MINOR;
1170 dev->dev_user.name = "nvmap";
1171 dev->dev_user.fops = &nvmap_user_fops;
1172 dev->dev_user.parent = &pdev->dev;
1173
1174 dev->dev_super.minor = MISC_DYNAMIC_MINOR;
1175 dev->dev_super.name = "knvmap";
1176 dev->dev_super.fops = &nvmap_super_fops;
1177 dev->dev_super.parent = &pdev->dev;
1178
1179 dev->handles = RB_ROOT;
1180
1181 init_waitqueue_head(&dev->pte_wait);
1182
1183 init_waitqueue_head(&dev->iovmm_master.pin_wait);
1184 mutex_init(&dev->iovmm_master.pin_lock);
1185 for (i = 0; i < NVMAP_NUM_POOLS; i++)
1186 nvmap_page_pool_init(&dev->iovmm_master.pools[i], i);
1187
1188 dev->iovmm_master.iovmm =
1189 tegra_iovmm_alloc_client(dev_name(&pdev->dev), NULL,
1190 &(dev->dev_user));
1191#ifdef CONFIG_TEGRA_IOVMM
1192 if (!dev->iovmm_master.iovmm) {
1193 e = PTR_ERR(dev->iovmm_master.iovmm);
1194 dev_err(&pdev->dev, "couldn't create iovmm client\n");
1195 goto fail;
1196 }
1197#endif
1198 dev->vm_rgn = alloc_vm_area(NVMAP_NUM_PTES * PAGE_SIZE);
1199 if (!dev->vm_rgn) {
1200 e = -ENOMEM;
1201 dev_err(&pdev->dev, "couldn't allocate remapping region\n");
1202 goto fail;
1203 }
1204 e = nvmap_mru_init(&dev->iovmm_master);
1205 if (e) {
1206 dev_err(&pdev->dev, "couldn't initialize MRU lists\n");
1207 goto fail;
1208 }
1209
1210 spin_lock_init(&dev->ptelock);
1211 spin_lock_init(&dev->handle_lock);
1212 INIT_LIST_HEAD(&dev->clients);
1213 spin_lock_init(&dev->clients_lock);
1214
1215 for (i = 0; i < NVMAP_NUM_PTES; i++) {
1216 unsigned long addr;
1217 pgd_t *pgd;
1218 pud_t *pud;
1219 pmd_t *pmd;
1220
1221 addr = (unsigned long)dev->vm_rgn->addr + (i * PAGE_SIZE);
1222 pgd = pgd_offset_k(addr);
1223 pud = pud_alloc(&init_mm, pgd, addr);
1224 if (!pud) {
1225 e = -ENOMEM;
1226 dev_err(&pdev->dev, "couldn't allocate page tables\n");
1227 goto fail;
1228 }
1229 pmd = pmd_alloc(&init_mm, pud, addr);
1230 if (!pmd) {
1231 e = -ENOMEM;
1232 dev_err(&pdev->dev, "couldn't allocate page tables\n");
1233 goto fail;
1234 }
1235 dev->ptes[i] = pte_alloc_kernel(pmd, addr);
1236 if (!dev->ptes[i]) {
1237 e = -ENOMEM;
1238 dev_err(&pdev->dev, "couldn't allocate page tables\n");
1239 goto fail;
1240 }
1241 }
1242
1243 e = misc_register(&dev->dev_user);
1244 if (e) {
1245 dev_err(&pdev->dev, "unable to register miscdevice %s\n",
1246 dev->dev_user.name);
1247 goto fail;
1248 }
1249
1250 e = misc_register(&dev->dev_super);
1251 if (e) {
1252 dev_err(&pdev->dev, "unable to register miscdevice %s\n",
1253 dev->dev_super.name);
1254 goto fail;
1255 }
1256
1257 dev->nr_carveouts = 0;
1258 dev->heaps = kzalloc(sizeof(struct nvmap_carveout_node) *
1259 plat->nr_carveouts, GFP_KERNEL);
1260 if (!dev->heaps) {
1261 e = -ENOMEM;
1262 dev_err(&pdev->dev, "couldn't allocate carveout memory\n");
1263 goto fail;
1264 }
1265
1266 nvmap_debug_root = debugfs_create_dir("nvmap", NULL);
1267 if (IS_ERR_OR_NULL(nvmap_debug_root))
1268 dev_err(&pdev->dev, "couldn't create debug files\n");
1269
1270 for (i = 0; i < plat->nr_carveouts; i++) {
1271 struct nvmap_carveout_node *node = &dev->heaps[dev->nr_carveouts];
1272 const struct nvmap_platform_carveout *co = &plat->carveouts[i];
1273 if (!co->size)
1274 continue;
1275 node->carveout = nvmap_heap_create(dev->dev_user.this_device,
1276 co->name, co->base, co->size,
1277 co->buddy_size, node);
1278 if (!node->carveout) {
1279 e = -ENOMEM;
1280 dev_err(&pdev->dev, "couldn't create %s\n", co->name);
1281 goto fail_heaps;
1282 }
1283 node->index = dev->nr_carveouts;
1284 dev->nr_carveouts++;
1285 spin_lock_init(&node->clients_lock);
1286 INIT_LIST_HEAD(&node->clients);
1287 node->heap_bit = co->usage_mask;
1288 if (nvmap_heap_create_group(node->carveout,
1289 &heap_extra_attr_group))
1290 dev_warn(&pdev->dev, "couldn't add extra attributes\n");
1291
1292 dev_info(&pdev->dev, "created carveout %s (%uKiB)\n",
1293 co->name, co->size / 1024);
1294
1295 if (!IS_ERR_OR_NULL(nvmap_debug_root)) {
1296 struct dentry *heap_root =
1297 debugfs_create_dir(co->name, nvmap_debug_root);
1298 if (!IS_ERR_OR_NULL(heap_root)) {
1299 debugfs_create_file("clients", 0664, heap_root,
1300 node, &debug_clients_fops);
1301 debugfs_create_file("allocations", 0664,
1302 heap_root, node, &debug_allocations_fops);
1303 }
1304 }
1305 }
1306 if (!IS_ERR_OR_NULL(nvmap_debug_root)) {
1307 struct dentry *iovmm_root =
1308 debugfs_create_dir("iovmm", nvmap_debug_root);
1309 if (!IS_ERR_OR_NULL(iovmm_root)) {
1310 debugfs_create_file("clients", 0664, iovmm_root,
1311 dev, &debug_iovmm_clients_fops);
1312 debugfs_create_file("allocations", 0664, iovmm_root,
1313 dev, &debug_iovmm_allocations_fops);
1314 for (i = 0; i < NVMAP_NUM_POOLS; i++) {
1315 char name[40];
1316 char *memtype_string[] = {"uc", "wc",
1317 "iwb", "wb"};
1318 sprintf(name, "%s_page_pool_available_pages",
1319 memtype_string[i]);
1320 debugfs_create_u32(name, S_IRUGO|S_IWUSR,
1321 iovmm_root,
1322 &dev->iovmm_master.pools[i].npages);
1323 }
1324 }
1325 }
1326
1327 platform_set_drvdata(pdev, dev);
1328 nvmap_dev = dev;
1329
1330 return 0;
1331fail_heaps:
1332 for (i = 0; i < dev->nr_carveouts; i++) {
1333 struct nvmap_carveout_node *node = &dev->heaps[i];
1334 nvmap_heap_remove_group(node->carveout, &heap_extra_attr_group);
1335 nvmap_heap_destroy(node->carveout);
1336 }
1337fail:
1338 kfree(dev->heaps);
1339 nvmap_mru_destroy(&dev->iovmm_master);
1340 if (dev->dev_super.minor != MISC_DYNAMIC_MINOR)
1341 misc_deregister(&dev->dev_super);
1342 if (dev->dev_user.minor != MISC_DYNAMIC_MINOR)
1343 misc_deregister(&dev->dev_user);
1344 if (!IS_ERR_OR_NULL(dev->iovmm_master.iovmm))
1345 tegra_iovmm_free_client(dev->iovmm_master.iovmm);
1346 if (dev->vm_rgn)
1347 free_vm_area(dev->vm_rgn);
1348 kfree(dev);
1349 nvmap_dev = NULL;
1350 return e;
1351}
1352
1353static int nvmap_remove(struct platform_device *pdev)
1354{
1355 struct nvmap_device *dev = platform_get_drvdata(pdev);
1356 struct rb_node *n;
1357 struct nvmap_handle *h;
1358 int i;
1359
1360 misc_deregister(&dev->dev_super);
1361 misc_deregister(&dev->dev_user);
1362
1363 while ((n = rb_first(&dev->handles))) {
1364 h = rb_entry(n, struct nvmap_handle, node);
1365 rb_erase(&h->node, &dev->handles);
1366 kfree(h);
1367 }
1368
1369 if (!IS_ERR_OR_NULL(dev->iovmm_master.iovmm))
1370 tegra_iovmm_free_client(dev->iovmm_master.iovmm);
1371
1372 nvmap_mru_destroy(&dev->iovmm_master);
1373
1374 for (i = 0; i < dev->nr_carveouts; i++) {
1375 struct nvmap_carveout_node *node = &dev->heaps[i];
1376 nvmap_heap_remove_group(node->carveout, &heap_extra_attr_group);
1377 nvmap_heap_destroy(node->carveout);
1378 }
1379 kfree(dev->heaps);
1380
1381 free_vm_area(dev->vm_rgn);
1382 kfree(dev);
1383 nvmap_dev = NULL;
1384 return 0;
1385}
1386
1387static int nvmap_suspend(struct platform_device *pdev, pm_message_t state)
1388{
1389 return 0;
1390}
1391
1392static int nvmap_resume(struct platform_device *pdev)
1393{
1394 return 0;
1395}
1396
1397static struct platform_driver nvmap_driver = {
1398 .probe = nvmap_probe,
1399 .remove = nvmap_remove,
1400 .suspend = nvmap_suspend,
1401 .resume = nvmap_resume,
1402
1403 .driver = {
1404 .name = "tegra-nvmap",
1405 .owner = THIS_MODULE,
1406 },
1407};
1408
1409static int __init nvmap_init_driver(void)
1410{
1411 int e;
1412
1413 nvmap_dev = NULL;
1414
1415 e = nvmap_heap_init();
1416 if (e)
1417 goto fail;
1418
1419 e = platform_driver_register(&nvmap_driver);
1420 if (e) {
1421 nvmap_heap_deinit();
1422 goto fail;
1423 }
1424
1425fail:
1426 return e;
1427}
1428fs_initcall(nvmap_init_driver);
1429
1430static void __exit nvmap_exit_driver(void)
1431{
1432 platform_driver_unregister(&nvmap_driver);
1433 nvmap_heap_deinit();
1434 nvmap_dev = NULL;
1435}
1436module_exit(nvmap_exit_driver);
diff --git a/drivers/video/tegra/nvmap/nvmap_handle.c b/drivers/video/tegra/nvmap/nvmap_handle.c
new file mode 100644
index 00000000000..539b7ce9801
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_handle.c
@@ -0,0 +1,1020 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_handle.c
3 *
4 * Handle allocation and freeing routines for nvmap
5 *
6 * Copyright (c) 2009-2012, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#define pr_fmt(fmt) "%s: " fmt, __func__
24
25#include <linux/err.h>
26#include <linux/kernel.h>
27#include <linux/list.h>
28#include <linux/mm.h>
29#include <linux/rbtree.h>
30#include <linux/slab.h>
31#include <linux/vmalloc.h>
32#include <linux/fs.h>
33
34#include <asm/cacheflush.h>
35#include <asm/outercache.h>
36#include <asm/pgtable.h>
37
38#include <mach/iovmm.h>
39#include <mach/nvmap.h>
40
41#include <linux/vmstat.h>
42#include <linux/swap.h>
43#include <linux/shrinker.h>
44#include <linux/moduleparam.h>
45
46#include "nvmap.h"
47#include "nvmap_mru.h"
48#include "nvmap_common.h"
49
50#define PRINT_CARVEOUT_CONVERSION 0
51#if PRINT_CARVEOUT_CONVERSION
52#define PR_INFO pr_info
53#else
54#define PR_INFO(...)
55#endif
56
57#define NVMAP_SECURE_HEAPS (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_IOVMM | \
58 NVMAP_HEAP_CARVEOUT_VPR)
59#ifdef CONFIG_NVMAP_HIGHMEM_ONLY
60#define GFP_NVMAP (__GFP_HIGHMEM | __GFP_NOWARN)
61#else
62#define GFP_NVMAP (GFP_KERNEL | __GFP_HIGHMEM | __GFP_NOWARN)
63#endif
64/* handles may be arbitrarily large (16+MiB), and any handle allocated from
65 * the kernel (i.e., not a carveout handle) includes its array of pages. to
66 * preserve kmalloc space, if the array of pages exceeds PAGELIST_VMALLOC_MIN,
67 * the array is allocated using vmalloc. */
68#define PAGELIST_VMALLOC_MIN (PAGE_SIZE * 2)
69#define NVMAP_TEST_PAGE_POOL_SHRINKER 1
70static bool enable_pp = 1;
71static int pool_size[NVMAP_NUM_POOLS];
72
73static char *s_memtype_str[] = {
74 "uc",
75 "wc",
76 "iwb",
77 "wb",
78};
79
80static inline void nvmap_page_pool_lock(struct nvmap_page_pool *pool)
81{
82 mutex_lock(&pool->lock);
83}
84
85static inline void nvmap_page_pool_unlock(struct nvmap_page_pool *pool)
86{
87 mutex_unlock(&pool->lock);
88}
89
90static struct page *nvmap_page_pool_alloc_locked(struct nvmap_page_pool *pool)
91{
92 struct page *page = NULL;
93
94 if (pool->npages > 0)
95 page = pool->page_array[--pool->npages];
96 return page;
97}
98
99static struct page *nvmap_page_pool_alloc(struct nvmap_page_pool *pool)
100{
101 struct page *page = NULL;
102
103 if (pool) {
104 nvmap_page_pool_lock(pool);
105 page = nvmap_page_pool_alloc_locked(pool);
106 nvmap_page_pool_unlock(pool);
107 }
108 return page;
109}
110
111static bool nvmap_page_pool_release_locked(struct nvmap_page_pool *pool,
112 struct page *page)
113{
114 int ret = false;
115
116 if (enable_pp && pool->npages < pool->max_pages) {
117 pool->page_array[pool->npages++] = page;
118 ret = true;
119 }
120 return ret;
121}
122
123static bool nvmap_page_pool_release(struct nvmap_page_pool *pool,
124 struct page *page)
125{
126 int ret = false;
127
128 if (pool) {
129 nvmap_page_pool_lock(pool);
130 ret = nvmap_page_pool_release_locked(pool, page);
131 nvmap_page_pool_unlock(pool);
132 }
133 return ret;
134}
135
136static int nvmap_page_pool_get_available_count(struct nvmap_page_pool *pool)
137{
138 return pool->npages;
139}
140
141static int nvmap_page_pool_free(struct nvmap_page_pool *pool, int nr_free)
142{
143 int i = nr_free;
144 int idx = 0;
145 struct page *page;
146
147 if (!nr_free)
148 return nr_free;
149 nvmap_page_pool_lock(pool);
150 while (i) {
151 page = nvmap_page_pool_alloc_locked(pool);
152 if (!page)
153 break;
154 pool->shrink_array[idx++] = page;
155 i--;
156 }
157
158 if (idx)
159 set_pages_array_wb(pool->shrink_array, idx);
160 while (idx--)
161 __free_page(pool->shrink_array[idx]);
162 nvmap_page_pool_unlock(pool);
163 return i;
164}
165
166static int nvmap_page_pool_get_unused_pages(void)
167{
168 unsigned int i;
169 int total = 0;
170 struct nvmap_share *share = nvmap_get_share_from_dev(nvmap_dev);
171
172 for (i = 0; i < NVMAP_NUM_POOLS; i++)
173 total += nvmap_page_pool_get_available_count(&share->pools[i]);
174
175 return total;
176}
177
178static void nvmap_page_pool_resize(struct nvmap_page_pool *pool, int size)
179{
180 int available_pages;
181 int pages_to_release = 0;
182 struct page **page_array = NULL;
183 struct page **shrink_array = NULL;
184
185 if (size == pool->max_pages)
186 return;
187repeat:
188 nvmap_page_pool_free(pool, pages_to_release);
189 nvmap_page_pool_lock(pool);
190 available_pages = nvmap_page_pool_get_available_count(pool);
191 if (available_pages > size) {
192 nvmap_page_pool_unlock(pool);
193 pages_to_release = available_pages - size;
194 goto repeat;
195 }
196
197 if (size == 0) {
198 vfree(pool->page_array);
199 vfree(pool->shrink_array);
200 pool->page_array = pool->shrink_array = NULL;
201 goto out;
202 }
203
204 page_array = vmalloc(sizeof(struct page *) * size);
205 shrink_array = vmalloc(sizeof(struct page *) * size);
206 if (!page_array || !shrink_array)
207 goto fail;
208
209 memcpy(page_array, pool->page_array,
210 pool->npages * sizeof(struct page *));
211 vfree(pool->page_array);
212 vfree(pool->shrink_array);
213 pool->page_array = page_array;
214 pool->shrink_array = shrink_array;
215out:
216 pr_debug("%s pool resized to %d from %d pages",
217 s_memtype_str[pool->flags], size, pool->max_pages);
218 pool->max_pages = size;
219 goto exit;
220fail:
221 vfree(page_array);
222 vfree(shrink_array);
223 pr_err("failed");
224exit:
225 nvmap_page_pool_unlock(pool);
226}
227
228static int nvmap_page_pool_shrink(struct shrinker *shrinker,
229 struct shrink_control *sc)
230{
231 unsigned int i;
232 unsigned int pool_offset;
233 struct nvmap_page_pool *pool;
234 int shrink_pages = sc->nr_to_scan;
235 static atomic_t start_pool = ATOMIC_INIT(-1);
236 struct nvmap_share *share = nvmap_get_share_from_dev(nvmap_dev);
237
238 if (!shrink_pages)
239 goto out;
240
241 pr_debug("sh_pages=%d", shrink_pages);
242
243 for (i = 0; i < NVMAP_NUM_POOLS && shrink_pages; i++) {
244 pool_offset = atomic_add_return(1, &start_pool) %
245 NVMAP_NUM_POOLS;
246 pool = &share->pools[pool_offset];
247 shrink_pages = nvmap_page_pool_free(pool, shrink_pages);
248 }
249out:
250 return nvmap_page_pool_get_unused_pages();
251}
252
253static struct shrinker nvmap_page_pool_shrinker = {
254 .shrink = nvmap_page_pool_shrink,
255 .seeks = 1,
256};
257
258static void shrink_page_pools(int *total_pages, int *available_pages)
259{
260 struct shrink_control sc;
261
262 sc.gfp_mask = GFP_KERNEL;
263 sc.nr_to_scan = 0;
264 *total_pages = nvmap_page_pool_shrink(NULL, &sc);
265 sc.nr_to_scan = *total_pages * 2;
266 *available_pages = nvmap_page_pool_shrink(NULL, &sc);
267}
268
269#if NVMAP_TEST_PAGE_POOL_SHRINKER
270static bool shrink_pp;
271static int shrink_set(const char *arg, const struct kernel_param *kp)
272{
273 int cpu = smp_processor_id();
274 unsigned long long t1, t2;
275 int total_pages, available_pages;
276
277 param_set_bool(arg, kp);
278
279 if (shrink_pp) {
280 t1 = cpu_clock(cpu);
281 shrink_page_pools(&total_pages, &available_pages);
282 t2 = cpu_clock(cpu);
283 pr_info("shrink page pools: time=%lldns, "
284 "total_pages_released=%d, free_pages_available=%d",
285 t2-t1, total_pages, available_pages);
286 }
287 return 0;
288}
289
290static int shrink_get(char *buff, const struct kernel_param *kp)
291{
292 return param_get_bool(buff, kp);
293}
294
295static struct kernel_param_ops shrink_ops = {
296 .get = shrink_get,
297 .set = shrink_set,
298};
299
300module_param_cb(shrink_page_pools, &shrink_ops, &shrink_pp, 0644);
301#endif
302
303static int enable_pp_set(const char *arg, const struct kernel_param *kp)
304{
305 int total_pages, available_pages;
306
307 param_set_bool(arg, kp);
308
309 if (!enable_pp) {
310 shrink_page_pools(&total_pages, &available_pages);
311 pr_info("disabled page pools and released pages, "
312 "total_pages_released=%d, free_pages_available=%d",
313 total_pages, available_pages);
314 }
315 return 0;
316}
317
318static int enable_pp_get(char *buff, const struct kernel_param *kp)
319{
320 return param_get_int(buff, kp);
321}
322
323static struct kernel_param_ops enable_pp_ops = {
324 .get = enable_pp_get,
325 .set = enable_pp_set,
326};
327
328module_param_cb(enable_page_pools, &enable_pp_ops, &enable_pp, 0644);
329
330#define POOL_SIZE_SET(m, i) \
331static int pool_size_##m##_set(const char *arg, const struct kernel_param *kp) \
332{ \
333 struct nvmap_share *share = nvmap_get_share_from_dev(nvmap_dev); \
334 param_set_int(arg, kp); \
335 nvmap_page_pool_resize(&share->pools[i], pool_size[i]); \
336 return 0; \
337}
338
339#define POOL_SIZE_GET(m) \
340static int pool_size_##m##_get(char *buff, const struct kernel_param *kp) \
341{ \
342 return param_get_int(buff, kp); \
343}
344
345#define POOL_SIZE_OPS(m) \
346static struct kernel_param_ops pool_size_##m##_ops = { \
347 .get = pool_size_##m##_get, \
348 .set = pool_size_##m##_set, \
349};
350
351#define POOL_SIZE_MOUDLE_PARAM_CB(m, i) \
352module_param_cb(m##_pool_size, &pool_size_##m##_ops, &pool_size[i], 0644)
353
354POOL_SIZE_SET(uc, NVMAP_HANDLE_UNCACHEABLE);
355POOL_SIZE_GET(uc);
356POOL_SIZE_OPS(uc);
357POOL_SIZE_MOUDLE_PARAM_CB(uc, NVMAP_HANDLE_UNCACHEABLE);
358
359POOL_SIZE_SET(wc, NVMAP_HANDLE_WRITE_COMBINE);
360POOL_SIZE_GET(wc);
361POOL_SIZE_OPS(wc);
362POOL_SIZE_MOUDLE_PARAM_CB(wc, NVMAP_HANDLE_WRITE_COMBINE);
363
364POOL_SIZE_SET(iwb, NVMAP_HANDLE_INNER_CACHEABLE);
365POOL_SIZE_GET(iwb);
366POOL_SIZE_OPS(iwb);
367POOL_SIZE_MOUDLE_PARAM_CB(iwb, NVMAP_HANDLE_INNER_CACHEABLE);
368
369POOL_SIZE_SET(wb, NVMAP_HANDLE_CACHEABLE);
370POOL_SIZE_GET(wb);
371POOL_SIZE_OPS(wb);
372POOL_SIZE_MOUDLE_PARAM_CB(wb, NVMAP_HANDLE_CACHEABLE);
373
374int nvmap_page_pool_init(struct nvmap_page_pool *pool, int flags)
375{
376 struct page *page;
377 int i;
378 static int reg = 1;
379 struct sysinfo info;
380 typedef int (*set_pages_array) (struct page **pages, int addrinarray);
381 set_pages_array s_cpa[] = {
382 set_pages_array_uc,
383 set_pages_array_wc,
384 set_pages_array_iwb,
385 set_pages_array_wb
386 };
387
388 BUG_ON(flags >= NVMAP_NUM_POOLS);
389 memset(pool, 0x0, sizeof(*pool));
390 mutex_init(&pool->lock);
391 pool->flags = flags;
392
393 /* No default pool for cached memory. */
394 if (flags == NVMAP_HANDLE_CACHEABLE)
395 return 0;
396
397 si_meminfo(&info);
398 if (!pool_size[flags]) {
399 /* Use 3/8th of total ram for page pools.
400 * 1/8th for uc, 1/8th for wc and 1/8th for iwb.
401 */
402 pool->max_pages = info.totalram >> 3;
403 }
404 if (pool->max_pages <= 0 || pool->max_pages >= info.totalram)
405 pool->max_pages = NVMAP_DEFAULT_PAGE_POOL_SIZE;
406 pool_size[flags] = pool->max_pages;
407 pr_info("nvmap %s page pool size=%d pages",
408 s_memtype_str[flags], pool->max_pages);
409 pool->page_array = vmalloc(sizeof(void *) * pool->max_pages);
410 pool->shrink_array = vmalloc(sizeof(struct page *) * pool->max_pages);
411 if (!pool->page_array || !pool->shrink_array)
412 goto fail;
413
414 if (reg) {
415 reg = 0;
416 register_shrinker(&nvmap_page_pool_shrinker);
417 }
418
419 nvmap_page_pool_lock(pool);
420 for (i = 0; i < pool->max_pages; i++) {
421 page = alloc_page(GFP_NVMAP);
422 if (!page)
423 goto do_cpa;
424 if (!nvmap_page_pool_release_locked(pool, page)) {
425 __free_page(page);
426 goto do_cpa;
427 }
428 }
429do_cpa:
430 (*s_cpa[flags])(pool->page_array, pool->npages);
431 nvmap_page_pool_unlock(pool);
432 return 0;
433fail:
434 pool->max_pages = 0;
435 vfree(pool->shrink_array);
436 vfree(pool->page_array);
437 return -ENOMEM;
438}
439
440static inline void *altalloc(size_t len)
441{
442 if (len >= PAGELIST_VMALLOC_MIN)
443 return vmalloc(len);
444 else
445 return kmalloc(len, GFP_KERNEL);
446}
447
448static inline void altfree(void *ptr, size_t len)
449{
450 if (!ptr)
451 return;
452
453 if (len >= PAGELIST_VMALLOC_MIN)
454 vfree(ptr);
455 else
456 kfree(ptr);
457}
458
459void _nvmap_handle_free(struct nvmap_handle *h)
460{
461 struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
462 unsigned int i, nr_page, page_index = 0;
463 struct nvmap_page_pool *pool = NULL;
464
465 if (nvmap_handle_remove(h->dev, h) != 0)
466 return;
467
468 if (!h->alloc)
469 goto out;
470
471 if (!h->heap_pgalloc) {
472 nvmap_usecount_inc(h);
473 nvmap_heap_free(h->carveout);
474 goto out;
475 }
476
477 nr_page = DIV_ROUND_UP(h->size, PAGE_SIZE);
478
479 BUG_ON(h->size & ~PAGE_MASK);
480 BUG_ON(!h->pgalloc.pages);
481
482 nvmap_mru_remove(share, h);
483
484 if (h->flags < NVMAP_NUM_POOLS)
485 pool = &share->pools[h->flags];
486
487 while (page_index < nr_page) {
488 if (!nvmap_page_pool_release(pool,
489 h->pgalloc.pages[page_index]))
490 break;
491 page_index++;
492 }
493
494 if (page_index == nr_page)
495 goto skip_attr_restore;
496
497 /* Restore page attributes. */
498 if (h->flags == NVMAP_HANDLE_WRITE_COMBINE ||
499 h->flags == NVMAP_HANDLE_UNCACHEABLE ||
500 h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
501 set_pages_array_wb(&h->pgalloc.pages[page_index],
502 nr_page - page_index);
503
504skip_attr_restore:
505 if (h->pgalloc.area)
506 tegra_iovmm_free_vm(h->pgalloc.area);
507
508 for (i = page_index; i < nr_page; i++)
509 __free_page(h->pgalloc.pages[i]);
510
511 altfree(h->pgalloc.pages, nr_page * sizeof(struct page *));
512
513out:
514 kfree(h);
515}
516
517static struct page *nvmap_alloc_pages_exact(gfp_t gfp, size_t size)
518{
519 struct page *page, *p, *e;
520 unsigned int order;
521
522 size = PAGE_ALIGN(size);
523 order = get_order(size);
524 page = alloc_pages(gfp, order);
525
526 if (!page)
527 return NULL;
528
529 split_page(page, order);
530 e = page + (1 << order);
531 for (p = page + (size >> PAGE_SHIFT); p < e; p++)
532 __free_page(p);
533
534 return page;
535}
536
537static int handle_page_alloc(struct nvmap_client *client,
538 struct nvmap_handle *h, bool contiguous)
539{
540 size_t size = PAGE_ALIGN(h->size);
541 struct nvmap_share *share = nvmap_get_share_from_dev(h->dev);
542 unsigned int nr_page = size >> PAGE_SHIFT;
543 pgprot_t prot;
544 unsigned int i = 0, page_index = 0;
545 struct page **pages;
546 struct nvmap_page_pool *pool = NULL;
547
548 pages = altalloc(nr_page * sizeof(*pages));
549 if (!pages)
550 return -ENOMEM;
551
552 prot = nvmap_pgprot(h, pgprot_kernel);
553
554 h->pgalloc.area = NULL;
555 if (contiguous) {
556 struct page *page;
557 page = nvmap_alloc_pages_exact(GFP_NVMAP, size);
558 if (!page)
559 goto fail;
560
561 for (i = 0; i < nr_page; i++)
562 pages[i] = nth_page(page, i);
563
564 } else {
565 if (h->flags < NVMAP_NUM_POOLS)
566 pool = &share->pools[h->flags];
567
568 for (i = 0; i < nr_page; i++) {
569 /* Get pages from pool, if available. */
570 pages[i] = nvmap_page_pool_alloc(pool);
571 if (!pages[i])
572 break;
573 page_index++;
574 }
575
576 for (; i < nr_page; i++) {
577 pages[i] = nvmap_alloc_pages_exact(GFP_NVMAP,
578 PAGE_SIZE);
579 if (!pages[i])
580 goto fail;
581 }
582
583#ifndef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
584 h->pgalloc.area = tegra_iovmm_create_vm(client->share->iovmm,
585 NULL, size, h->align, prot,
586 h->pgalloc.iovm_addr);
587 if (!h->pgalloc.area)
588 goto fail;
589
590 h->pgalloc.dirty = true;
591#endif
592 }
593
594 if (nr_page == page_index)
595 goto skip_attr_change;
596
597 /* Update the pages mapping in kernel page table. */
598 if (h->flags == NVMAP_HANDLE_WRITE_COMBINE)
599 set_pages_array_wc(&pages[page_index],
600 nr_page - page_index);
601 else if (h->flags == NVMAP_HANDLE_UNCACHEABLE)
602 set_pages_array_uc(&pages[page_index],
603 nr_page - page_index);
604 else if (h->flags == NVMAP_HANDLE_INNER_CACHEABLE)
605 set_pages_array_iwb(&pages[page_index],
606 nr_page - page_index);
607
608skip_attr_change:
609 h->size = size;
610 h->pgalloc.pages = pages;
611 h->pgalloc.contig = contiguous;
612 INIT_LIST_HEAD(&h->pgalloc.mru_list);
613 return 0;
614
615fail:
616 while (i--) {
617 set_pages_array_wb(&pages[i], 1);
618 __free_page(pages[i]);
619 }
620 altfree(pages, nr_page * sizeof(*pages));
621 wmb();
622 return -ENOMEM;
623}
624
625static void alloc_handle(struct nvmap_client *client,
626 struct nvmap_handle *h, unsigned int type)
627{
628 BUG_ON(type & (type - 1));
629
630#ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
631#define __NVMAP_HEAP_CARVEOUT (NVMAP_HEAP_CARVEOUT_IRAM | NVMAP_HEAP_CARVEOUT_VPR)
632#define __NVMAP_HEAP_IOVMM (NVMAP_HEAP_IOVMM | NVMAP_HEAP_CARVEOUT_GENERIC)
633 if (type & NVMAP_HEAP_CARVEOUT_GENERIC) {
634#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
635 if (h->size <= PAGE_SIZE) {
636 PR_INFO("###CARVEOUT CONVERTED TO SYSMEM "
637 "0x%x bytes %s(%d)###\n",
638 h->size, current->comm, current->pid);
639 goto sysheap;
640 }
641#endif
642 PR_INFO("###CARVEOUT CONVERTED TO IOVM "
643 "0x%x bytes %s(%d)###\n",
644 h->size, current->comm, current->pid);
645 }
646#else
647#define __NVMAP_HEAP_CARVEOUT NVMAP_HEAP_CARVEOUT_MASK
648#define __NVMAP_HEAP_IOVMM NVMAP_HEAP_IOVMM
649#endif
650
651 if (type & __NVMAP_HEAP_CARVEOUT) {
652 struct nvmap_heap_block *b;
653#ifdef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
654 PR_INFO("###IRAM REQUEST RETAINED "
655 "0x%x bytes %s(%d)###\n",
656 h->size, current->comm, current->pid);
657#endif
658 /* Protect handle from relocation */
659 nvmap_usecount_inc(h);
660
661 b = nvmap_carveout_alloc(client, h, type);
662 if (b) {
663 h->heap_pgalloc = false;
664 h->alloc = true;
665 nvmap_carveout_commit_add(client,
666 nvmap_heap_to_arg(nvmap_block_to_heap(b)),
667 h->size);
668 }
669 nvmap_usecount_dec(h);
670
671 } else if (type & __NVMAP_HEAP_IOVMM) {
672 size_t reserved = PAGE_ALIGN(h->size);
673 int commit = 0;
674 int ret;
675
676 /* increment the committed IOVM space prior to allocation
677 * to avoid race conditions with other threads simultaneously
678 * allocating. */
679 commit = atomic_add_return(reserved,
680 &client->iovm_commit);
681
682 if (commit < client->iovm_limit)
683 ret = handle_page_alloc(client, h, false);
684 else
685 ret = -ENOMEM;
686
687 if (!ret) {
688 h->heap_pgalloc = true;
689 h->alloc = true;
690 } else {
691 atomic_sub(reserved, &client->iovm_commit);
692 }
693
694 } else if (type & NVMAP_HEAP_SYSMEM) {
695#if defined(CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM) && \
696 defined(CONFIG_NVMAP_ALLOW_SYSMEM)
697sysheap:
698#endif
699 if (handle_page_alloc(client, h, true) == 0) {
700 BUG_ON(!h->pgalloc.contig);
701 h->heap_pgalloc = true;
702 h->alloc = true;
703 }
704 }
705}
706
707/* small allocations will try to allocate from generic OS memory before
708 * any of the limited heaps, to increase the effective memory for graphics
709 * allocations, and to reduce fragmentation of the graphics heaps with
710 * sub-page splinters */
711static const unsigned int heap_policy_small[] = {
712 NVMAP_HEAP_CARVEOUT_VPR,
713 NVMAP_HEAP_CARVEOUT_IRAM,
714#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
715 NVMAP_HEAP_SYSMEM,
716#endif
717 NVMAP_HEAP_CARVEOUT_MASK,
718 NVMAP_HEAP_IOVMM,
719 0,
720};
721
722static const unsigned int heap_policy_large[] = {
723 NVMAP_HEAP_CARVEOUT_VPR,
724 NVMAP_HEAP_CARVEOUT_IRAM,
725 NVMAP_HEAP_IOVMM,
726 NVMAP_HEAP_CARVEOUT_MASK,
727#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
728 NVMAP_HEAP_SYSMEM,
729#endif
730 0,
731};
732
733/* Do not override single page policy if there is not much space to
734avoid invoking system oom killer. */
735#define NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD 50000000
736
737int nvmap_alloc_handle_id(struct nvmap_client *client,
738 unsigned long id, unsigned int heap_mask,
739 size_t align, unsigned int flags)
740{
741 struct nvmap_handle *h = NULL;
742 const unsigned int *alloc_policy;
743 int nr_page;
744 int err = -ENOMEM;
745
746 h = nvmap_get_handle_id(client, id);
747
748 if (!h)
749 return -EINVAL;
750
751 if (h->alloc)
752 goto out;
753
754 h->userflags = flags;
755 nr_page = ((h->size + PAGE_SIZE - 1) >> PAGE_SHIFT);
756 h->secure = !!(flags & NVMAP_HANDLE_SECURE);
757 h->flags = (flags & NVMAP_HANDLE_CACHE_FLAG);
758 h->align = max_t(size_t, align, L1_CACHE_BYTES);
759
760#ifndef CONFIG_TEGRA_IOVMM
761 if (heap_mask & NVMAP_HEAP_IOVMM) {
762 heap_mask &= NVMAP_HEAP_IOVMM;
763 heap_mask |= NVMAP_HEAP_CARVEOUT_GENERIC;
764 }
765#endif
766#ifndef CONFIG_NVMAP_CONVERT_CARVEOUT_TO_IOVMM
767#ifdef CONFIG_NVMAP_ALLOW_SYSMEM
768 /* Allow single pages allocations in system memory to save
769 * carveout space and avoid extra iovm mappings */
770 if (nr_page == 1) {
771 if (heap_mask & NVMAP_HEAP_IOVMM)
772 heap_mask |= NVMAP_HEAP_SYSMEM;
773 else if (heap_mask & NVMAP_HEAP_CARVEOUT_GENERIC) {
774 /* Calculate size of free physical pages
775 * managed by kernel */
776 unsigned long freeMem =
777 (global_page_state(NR_FREE_PAGES) +
778 global_page_state(NR_FILE_PAGES) -
779 total_swapcache_pages) << PAGE_SHIFT;
780
781 if (freeMem > NVMAP_SMALL_POLICY_SYSMEM_THRESHOLD)
782 heap_mask |= NVMAP_HEAP_SYSMEM;
783 }
784 }
785#endif
786
787 /* This restriction is deprecated as alignments greater than
788 PAGE_SIZE are now correctly handled, but it is retained for
789 AP20 compatibility. */
790 if (h->align > PAGE_SIZE)
791 heap_mask &= NVMAP_HEAP_CARVEOUT_MASK;
792#endif
793 /* secure allocations can only be served from secure heaps */
794 if (h->secure)
795 heap_mask &= NVMAP_SECURE_HEAPS;
796
797 if (!heap_mask) {
798 err = -EINVAL;
799 goto out;
800 }
801
802 alloc_policy = (nr_page == 1) ? heap_policy_small : heap_policy_large;
803
804 while (!h->alloc && *alloc_policy) {
805 unsigned int heap_type;
806
807 heap_type = *alloc_policy++;
808 heap_type &= heap_mask;
809
810 if (!heap_type)
811 continue;
812
813 heap_mask &= ~heap_type;
814
815 while (heap_type && !h->alloc) {
816 unsigned int heap;
817
818 /* iterate possible heaps MSB-to-LSB, since higher-
819 * priority carveouts will have higher usage masks */
820 heap = 1 << __fls(heap_type);
821 alloc_handle(client, h, heap);
822 heap_type &= ~heap;
823 }
824 }
825
826out:
827 err = (h->alloc) ? 0 : err;
828 nvmap_handle_put(h);
829 return err;
830}
831
832void nvmap_free_handle_id(struct nvmap_client *client, unsigned long id)
833{
834 struct nvmap_handle_ref *ref;
835 struct nvmap_handle *h;
836 int pins;
837
838 nvmap_ref_lock(client);
839
840 ref = _nvmap_validate_id_locked(client, id);
841 if (!ref) {
842 nvmap_ref_unlock(client);
843 return;
844 }
845
846 BUG_ON(!ref->handle);
847 h = ref->handle;
848
849 if (atomic_dec_return(&ref->dupes)) {
850 nvmap_ref_unlock(client);
851 goto out;
852 }
853
854 smp_rmb();
855 pins = atomic_read(&ref->pin);
856 rb_erase(&ref->node, &client->handle_refs);
857
858 if (h->alloc && h->heap_pgalloc && !h->pgalloc.contig)
859 atomic_sub(h->size, &client->iovm_commit);
860
861 if (h->alloc && !h->heap_pgalloc) {
862 mutex_lock(&h->lock);
863 nvmap_carveout_commit_subtract(client,
864 nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
865 h->size);
866 mutex_unlock(&h->lock);
867 }
868
869 nvmap_ref_unlock(client);
870
871 if (pins)
872 nvmap_err(client, "%s freeing pinned handle %p\n",
873 current->group_leader->comm, h);
874
875 while (pins--)
876 nvmap_unpin_handles(client, &ref->handle, 1);
877
878 if (h->owner == client)
879 h->owner = NULL;
880
881 kfree(ref);
882
883out:
884 BUG_ON(!atomic_read(&h->ref));
885 nvmap_handle_put(h);
886}
887
888static void add_handle_ref(struct nvmap_client *client,
889 struct nvmap_handle_ref *ref)
890{
891 struct rb_node **p, *parent = NULL;
892
893 nvmap_ref_lock(client);
894 p = &client->handle_refs.rb_node;
895 while (*p) {
896 struct nvmap_handle_ref *node;
897 parent = *p;
898 node = rb_entry(parent, struct nvmap_handle_ref, node);
899 if (ref->handle > node->handle)
900 p = &parent->rb_right;
901 else
902 p = &parent->rb_left;
903 }
904 rb_link_node(&ref->node, parent, p);
905 rb_insert_color(&ref->node, &client->handle_refs);
906 nvmap_ref_unlock(client);
907}
908
909struct nvmap_handle_ref *nvmap_create_handle(struct nvmap_client *client,
910 size_t size)
911{
912 struct nvmap_handle *h;
913 struct nvmap_handle_ref *ref = NULL;
914
915 if (!client)
916 return ERR_PTR(-EINVAL);
917
918 if (!size)
919 return ERR_PTR(-EINVAL);
920
921 h = kzalloc(sizeof(*h), GFP_KERNEL);
922 if (!h)
923 return ERR_PTR(-ENOMEM);
924
925 ref = kzalloc(sizeof(*ref), GFP_KERNEL);
926 if (!ref) {
927 kfree(h);
928 return ERR_PTR(-ENOMEM);
929 }
930
931 atomic_set(&h->ref, 1);
932 atomic_set(&h->pin, 0);
933 h->owner = client;
934 h->dev = client->dev;
935 BUG_ON(!h->owner);
936 h->size = h->orig_size = size;
937 h->flags = NVMAP_HANDLE_WRITE_COMBINE;
938 mutex_init(&h->lock);
939
940 nvmap_handle_add(client->dev, h);
941
942 atomic_set(&ref->dupes, 1);
943 ref->handle = h;
944 atomic_set(&ref->pin, 0);
945 add_handle_ref(client, ref);
946 return ref;
947}
948
949struct nvmap_handle_ref *nvmap_duplicate_handle_id(struct nvmap_client *client,
950 unsigned long id)
951{
952 struct nvmap_handle_ref *ref = NULL;
953 struct nvmap_handle *h = NULL;
954
955 BUG_ON(!client || client->dev != nvmap_dev);
956 /* on success, the reference count for the handle should be
957 * incremented, so the success paths will not call nvmap_handle_put */
958 h = nvmap_validate_get(client, id);
959
960 if (!h) {
961 nvmap_debug(client, "%s duplicate handle failed\n",
962 current->group_leader->comm);
963 return ERR_PTR(-EPERM);
964 }
965
966 if (!h->alloc) {
967 nvmap_err(client, "%s duplicating unallocated handle\n",
968 current->group_leader->comm);
969 nvmap_handle_put(h);
970 return ERR_PTR(-EINVAL);
971 }
972
973 nvmap_ref_lock(client);
974 ref = _nvmap_validate_id_locked(client, (unsigned long)h);
975
976 if (ref) {
977 /* handle already duplicated in client; just increment
978 * the reference count rather than re-duplicating it */
979 atomic_inc(&ref->dupes);
980 nvmap_ref_unlock(client);
981 return ref;
982 }
983
984 nvmap_ref_unlock(client);
985
986 /* verify that adding this handle to the process' access list
987 * won't exceed the IOVM limit */
988 if (h->heap_pgalloc && !h->pgalloc.contig) {
989 int oc;
990 oc = atomic_add_return(h->size, &client->iovm_commit);
991 if (oc > client->iovm_limit && !client->super) {
992 atomic_sub(h->size, &client->iovm_commit);
993 nvmap_handle_put(h);
994 nvmap_err(client, "duplicating %p in %s over-commits"
995 " IOVMM space\n", (void *)id,
996 current->group_leader->comm);
997 return ERR_PTR(-ENOMEM);
998 }
999 }
1000
1001 ref = kzalloc(sizeof(*ref), GFP_KERNEL);
1002 if (!ref) {
1003 nvmap_handle_put(h);
1004 return ERR_PTR(-ENOMEM);
1005 }
1006
1007 if (!h->heap_pgalloc) {
1008 mutex_lock(&h->lock);
1009 nvmap_carveout_commit_add(client,
1010 nvmap_heap_to_arg(nvmap_block_to_heap(h->carveout)),
1011 h->size);
1012 mutex_unlock(&h->lock);
1013 }
1014
1015 atomic_set(&ref->dupes, 1);
1016 ref->handle = h;
1017 atomic_set(&ref->pin, 0);
1018 add_handle_ref(client, ref);
1019 return ref;
1020}
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.c b/drivers/video/tegra/nvmap/nvmap_heap.c
new file mode 100644
index 00000000000..7474f31534f
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_heap.c
@@ -0,0 +1,1113 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_heap.c
3 *
4 * GPU heap allocator.
5 *
6 * Copyright (c) 2011, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/device.h>
24#include <linux/kernel.h>
25#include <linux/list.h>
26#include <linux/mm.h>
27#include <linux/mutex.h>
28#include <linux/slab.h>
29#include <linux/err.h>
30
31#include <mach/nvmap.h>
32#include "nvmap.h"
33#include "nvmap_heap.h"
34#include "nvmap_common.h"
35
36#include <asm/tlbflush.h>
37#include <asm/cacheflush.h>
38
39/*
40 * "carveouts" are platform-defined regions of physically contiguous memory
41 * which are not managed by the OS. a platform may specify multiple carveouts,
42 * for either small special-purpose memory regions (like IRAM on Tegra SoCs)
43 * or reserved regions of main system memory.
44 *
45 * the carveout allocator returns allocations which are physically contiguous.
46 * to reduce external fragmentation, the allocation algorithm implemented in
47 * this file employs 3 strategies for keeping allocations of similar size
48 * grouped together inside the larger heap: the "small", "normal" and "huge"
49 * strategies. the size thresholds (in bytes) for determining which strategy
50 * to employ should be provided by the platform for each heap. it is possible
51 * for a platform to define a heap where only the "normal" strategy is used.
52 *
53 * o "normal" allocations use an address-order first-fit allocator (called
54 * BOTTOM_UP in the code below). each allocation is rounded up to be
55 * an integer multiple of the "small" allocation size.
56 *
57 * o "huge" allocations use an address-order last-fit allocator (called
58 * TOP_DOWN in the code below). like "normal" allocations, each allocation
59 * is rounded up to be an integer multiple of the "small" allocation size.
60 *
61 * o "small" allocations are treated differently: the heap manager maintains
62 * a pool of "small"-sized blocks internally from which allocations less
63 * than 1/2 of the "small" size are buddy-allocated. if a "small" allocation
64 * is requested and none of the buddy sub-heaps is able to service it,
65 * the heap manager will try to allocate a new buddy-heap.
66 *
67 * this allocator is intended to keep "splinters" colocated in the carveout,
68 * and to ensure that the minimum free block size in the carveout (i.e., the
69 * "small" threshold) is still a meaningful size.
70 *
71 */
72
73#define MAX_BUDDY_NR 128 /* maximum buddies in a buddy allocator */
74
75enum direction {
76 TOP_DOWN,
77 BOTTOM_UP
78};
79
80enum block_type {
81 BLOCK_FIRST_FIT, /* block was allocated directly from the heap */
82 BLOCK_BUDDY, /* block was allocated from a buddy sub-heap */
83 BLOCK_EMPTY,
84};
85
86struct heap_stat {
87 size_t free; /* total free size */
88 size_t free_largest; /* largest free block */
89 size_t free_count; /* number of free blocks */
90 size_t total; /* total size */
91 size_t largest; /* largest unique block */
92 size_t count; /* total number of blocks */
93 /* fast compaction attempt counter */
94 unsigned int compaction_count_fast;
95 /* full compaction attempt counter */
96 unsigned int compaction_count_full;
97};
98
99struct buddy_heap;
100
101struct buddy_block {
102 struct nvmap_heap_block block;
103 struct buddy_heap *heap;
104};
105
106struct list_block {
107 struct nvmap_heap_block block;
108 struct list_head all_list;
109 unsigned int mem_prot;
110 unsigned long orig_addr;
111 size_t size;
112 size_t align;
113 struct nvmap_heap *heap;
114 struct list_head free_list;
115};
116
117struct combo_block {
118 union {
119 struct list_block lb;
120 struct buddy_block bb;
121 };
122};
123
124struct buddy_bits {
125 unsigned int alloc:1;
126 unsigned int order:7; /* log2(MAX_BUDDY_NR); */
127};
128
129struct buddy_heap {
130 struct list_block *heap_base;
131 unsigned int nr_buddies;
132 struct list_head buddy_list;
133 struct buddy_bits bitmap[MAX_BUDDY_NR];
134};
135
136struct nvmap_heap {
137 struct list_head all_list;
138 struct list_head free_list;
139 struct mutex lock;
140 struct list_head buddy_list;
141 unsigned int min_buddy_shift;
142 unsigned int buddy_heap_size;
143 unsigned int small_alloc;
144 const char *name;
145 void *arg;
146 struct device dev;
147};
148
149static struct kmem_cache *buddy_heap_cache;
150static struct kmem_cache *block_cache;
151
152static inline struct nvmap_heap *parent_of(struct buddy_heap *heap)
153{
154 return heap->heap_base->heap;
155}
156
157static inline unsigned int order_of(size_t len, size_t min_shift)
158{
159 len = 2 * DIV_ROUND_UP(len, (1 << min_shift)) - 1;
160 return fls(len)-1;
161}
162
163/* returns the free size in bytes of the buddy heap; must be called while
164 * holding the parent heap's lock. */
165static void buddy_stat(struct buddy_heap *heap, struct heap_stat *stat)
166{
167 unsigned int index;
168 unsigned int shift = parent_of(heap)->min_buddy_shift;
169
170 for (index = 0; index < heap->nr_buddies;
171 index += (1 << heap->bitmap[index].order)) {
172 size_t curr = 1 << (heap->bitmap[index].order + shift);
173
174 stat->largest = max(stat->largest, curr);
175 stat->total += curr;
176 stat->count++;
177
178 if (!heap->bitmap[index].alloc) {
179 stat->free += curr;
180 stat->free_largest = max(stat->free_largest, curr);
181 stat->free_count++;
182 }
183 }
184}
185
186/* returns the free size of the heap (including any free blocks in any
187 * buddy-heap suballocators; must be called while holding the parent
188 * heap's lock. */
189static unsigned long heap_stat(struct nvmap_heap *heap, struct heap_stat *stat)
190{
191 struct buddy_heap *bh;
192 struct list_block *l = NULL;
193 unsigned long base = -1ul;
194
195 memset(stat, 0, sizeof(*stat));
196 mutex_lock(&heap->lock);
197 list_for_each_entry(l, &heap->all_list, all_list) {
198 stat->total += l->size;
199 stat->largest = max(l->size, stat->largest);
200 stat->count++;
201 base = min(base, l->orig_addr);
202 }
203
204 list_for_each_entry(bh, &heap->buddy_list, buddy_list) {
205 buddy_stat(bh, stat);
206 /* the total counts are double-counted for buddy heaps
207 * since the blocks allocated for buddy heaps exist in the
208 * all_list; subtract out the doubly-added stats */
209 stat->total -= bh->heap_base->size;
210 stat->count--;
211 }
212
213 list_for_each_entry(l, &heap->free_list, free_list) {
214 stat->free += l->size;
215 stat->free_count++;
216 stat->free_largest = max(l->size, stat->free_largest);
217 }
218 mutex_unlock(&heap->lock);
219
220 return base;
221}
222
223static ssize_t heap_name_show(struct device *dev,
224 struct device_attribute *attr, char *buf);
225
226static ssize_t heap_stat_show(struct device *dev,
227 struct device_attribute *attr, char *buf);
228
229static struct device_attribute heap_stat_total_max =
230 __ATTR(total_max, S_IRUGO, heap_stat_show, NULL);
231
232static struct device_attribute heap_stat_total_count =
233 __ATTR(total_count, S_IRUGO, heap_stat_show, NULL);
234
235static struct device_attribute heap_stat_total_size =
236 __ATTR(total_size, S_IRUGO, heap_stat_show, NULL);
237
238static struct device_attribute heap_stat_free_max =
239 __ATTR(free_max, S_IRUGO, heap_stat_show, NULL);
240
241static struct device_attribute heap_stat_free_count =
242 __ATTR(free_count, S_IRUGO, heap_stat_show, NULL);
243
244static struct device_attribute heap_stat_free_size =
245 __ATTR(free_size, S_IRUGO, heap_stat_show, NULL);
246
247static struct device_attribute heap_stat_base =
248 __ATTR(base, S_IRUGO, heap_stat_show, NULL);
249
250static struct device_attribute heap_attr_name =
251 __ATTR(name, S_IRUGO, heap_name_show, NULL);
252
253static struct attribute *heap_stat_attrs[] = {
254 &heap_stat_total_max.attr,
255 &heap_stat_total_count.attr,
256 &heap_stat_total_size.attr,
257 &heap_stat_free_max.attr,
258 &heap_stat_free_count.attr,
259 &heap_stat_free_size.attr,
260 &heap_stat_base.attr,
261 &heap_attr_name.attr,
262 NULL,
263};
264
265static struct attribute_group heap_stat_attr_group = {
266 .attrs = heap_stat_attrs,
267};
268
269static ssize_t heap_name_show(struct device *dev,
270 struct device_attribute *attr, char *buf)
271{
272
273 struct nvmap_heap *heap = container_of(dev, struct nvmap_heap, dev);
274 return sprintf(buf, "%s\n", heap->name);
275}
276
277static ssize_t heap_stat_show(struct device *dev,
278 struct device_attribute *attr, char *buf)
279{
280 struct nvmap_heap *heap = container_of(dev, struct nvmap_heap, dev);
281 struct heap_stat stat;
282 unsigned long base;
283
284 base = heap_stat(heap, &stat);
285
286 if (attr == &heap_stat_total_max)
287 return sprintf(buf, "%u\n", stat.largest);
288 else if (attr == &heap_stat_total_count)
289 return sprintf(buf, "%u\n", stat.count);
290 else if (attr == &heap_stat_total_size)
291 return sprintf(buf, "%u\n", stat.total);
292 else if (attr == &heap_stat_free_max)
293 return sprintf(buf, "%u\n", stat.free_largest);
294 else if (attr == &heap_stat_free_count)
295 return sprintf(buf, "%u\n", stat.free_count);
296 else if (attr == &heap_stat_free_size)
297 return sprintf(buf, "%u\n", stat.free);
298 else if (attr == &heap_stat_base)
299 return sprintf(buf, "%08lx\n", base);
300 else
301 return -EINVAL;
302}
303#ifndef CONFIG_NVMAP_CARVEOUT_COMPACTOR
304static struct nvmap_heap_block *buddy_alloc(struct buddy_heap *heap,
305 size_t size, size_t align,
306 unsigned int mem_prot)
307{
308 unsigned int index = 0;
309 unsigned int min_shift = parent_of(heap)->min_buddy_shift;
310 unsigned int order = order_of(size, min_shift);
311 unsigned int align_mask;
312 unsigned int best = heap->nr_buddies;
313 struct buddy_block *b;
314
315 if (heap->heap_base->mem_prot != mem_prot)
316 return NULL;
317
318 align = max(align, (size_t)(1 << min_shift));
319 align_mask = (align >> min_shift) - 1;
320
321 for (index = 0; index < heap->nr_buddies;
322 index += (1 << heap->bitmap[index].order)) {
323
324 if (heap->bitmap[index].alloc || (index & align_mask) ||
325 (heap->bitmap[index].order < order))
326 continue;
327
328 if (best == heap->nr_buddies ||
329 heap->bitmap[index].order < heap->bitmap[best].order)
330 best = index;
331
332 if (heap->bitmap[best].order == order)
333 break;
334 }
335
336 if (best == heap->nr_buddies)
337 return NULL;
338
339 b = kmem_cache_zalloc(block_cache, GFP_KERNEL);
340 if (!b)
341 return NULL;
342
343 while (heap->bitmap[best].order != order) {
344 unsigned int buddy;
345 heap->bitmap[best].order--;
346 buddy = best ^ (1 << heap->bitmap[best].order);
347 heap->bitmap[buddy].order = heap->bitmap[best].order;
348 heap->bitmap[buddy].alloc = 0;
349 }
350 heap->bitmap[best].alloc = 1;
351 b->block.base = heap->heap_base->block.base + (best << min_shift);
352 b->heap = heap;
353 b->block.type = BLOCK_BUDDY;
354 return &b->block;
355}
356#endif
357
358static struct buddy_heap *do_buddy_free(struct nvmap_heap_block *block)
359{
360 struct buddy_block *b = container_of(block, struct buddy_block, block);
361 struct buddy_heap *h = b->heap;
362 unsigned int min_shift = parent_of(h)->min_buddy_shift;
363 unsigned int index;
364
365 index = (block->base - h->heap_base->block.base) >> min_shift;
366 h->bitmap[index].alloc = 0;
367
368 for (;;) {
369 unsigned int buddy = index ^ (1 << h->bitmap[index].order);
370 if (buddy >= h->nr_buddies || h->bitmap[buddy].alloc ||
371 h->bitmap[buddy].order != h->bitmap[index].order)
372 break;
373
374 h->bitmap[buddy].order++;
375 h->bitmap[index].order++;
376 index = min(buddy, index);
377 }
378
379 kmem_cache_free(block_cache, b);
380 if ((1 << h->bitmap[0].order) == h->nr_buddies)
381 return h;
382
383 return NULL;
384}
385
386
387/*
388 * base_max limits position of allocated chunk in memory.
389 * if base_max is 0 then there is no such limitation.
390 */
391static struct nvmap_heap_block *do_heap_alloc(struct nvmap_heap *heap,
392 size_t len, size_t align,
393 unsigned int mem_prot,
394 unsigned long base_max)
395{
396 struct list_block *b = NULL;
397 struct list_block *i = NULL;
398 struct list_block *rem = NULL;
399 unsigned long fix_base;
400 enum direction dir;
401
402 /* since pages are only mappable with one cache attribute,
403 * and most allocations from carveout heaps are DMA coherent
404 * (i.e., non-cacheable), round cacheable allocations up to
405 * a page boundary to ensure that the physical pages will
406 * only be mapped one way. */
407 if (mem_prot == NVMAP_HANDLE_CACHEABLE ||
408 mem_prot == NVMAP_HANDLE_INNER_CACHEABLE) {
409 align = max_t(size_t, align, PAGE_SIZE);
410 len = PAGE_ALIGN(len);
411 }
412
413#ifdef CONFIG_NVMAP_CARVEOUT_COMPACTOR
414 dir = BOTTOM_UP;
415#else
416 dir = (len <= heap->small_alloc) ? BOTTOM_UP : TOP_DOWN;
417#endif
418
419 if (dir == BOTTOM_UP) {
420 list_for_each_entry(i, &heap->free_list, free_list) {
421 size_t fix_size;
422 fix_base = ALIGN(i->block.base, align);
423 fix_size = i->size - (fix_base - i->block.base);
424
425 /* needed for compaction. relocated chunk
426 * should never go up */
427 if (base_max && fix_base > base_max)
428 break;
429
430 if (fix_size >= len) {
431 b = i;
432 break;
433 }
434 }
435 } else {
436 list_for_each_entry_reverse(i, &heap->free_list, free_list) {
437 if (i->size >= len) {
438 fix_base = i->block.base + i->size - len;
439 fix_base &= ~(align-1);
440 if (fix_base >= i->block.base) {
441 b = i;
442 break;
443 }
444 }
445 }
446 }
447
448 if (!b)
449 return NULL;
450
451 if (dir == BOTTOM_UP)
452 b->block.type = BLOCK_FIRST_FIT;
453
454 /* split free block */
455 if (b->block.base != fix_base) {
456 /* insert a new free block before allocated */
457 rem = kmem_cache_zalloc(block_cache, GFP_KERNEL);
458 if (!rem) {
459 b->orig_addr = b->block.base;
460 b->block.base = fix_base;
461 b->size -= (b->block.base - b->orig_addr);
462 goto out;
463 }
464
465 rem->block.type = BLOCK_EMPTY;
466 rem->block.base = b->block.base;
467 rem->orig_addr = rem->block.base;
468 rem->size = fix_base - rem->block.base;
469 b->block.base = fix_base;
470 b->orig_addr = fix_base;
471 b->size -= rem->size;
472 list_add_tail(&rem->all_list, &b->all_list);
473 list_add_tail(&rem->free_list, &b->free_list);
474 }
475
476 b->orig_addr = b->block.base;
477
478 if (b->size > len) {
479 /* insert a new free block after allocated */
480 rem = kmem_cache_zalloc(block_cache, GFP_KERNEL);
481 if (!rem)
482 goto out;
483
484 rem->block.type = BLOCK_EMPTY;
485 rem->block.base = b->block.base + len;
486 rem->size = b->size - len;
487 BUG_ON(rem->size > b->size);
488 rem->orig_addr = rem->block.base;
489 b->size = len;
490 list_add(&rem->all_list, &b->all_list);
491 list_add(&rem->free_list, &b->free_list);
492 }
493
494out:
495 list_del(&b->free_list);
496 b->heap = heap;
497 b->mem_prot = mem_prot;
498 b->align = align;
499 return &b->block;
500}
501
502#ifdef DEBUG_FREE_LIST
503static void freelist_debug(struct nvmap_heap *heap, const char *title,
504 struct list_block *token)
505{
506 int i;
507 struct list_block *n;
508
509 dev_debug(&heap->dev, "%s\n", title);
510 i = 0;
511 list_for_each_entry(n, &heap->free_list, free_list) {
512 dev_debug(&heap->dev, "\t%d [%p..%p]%s\n", i, (void *)n->orig_addr,
513 (void *)(n->orig_addr + n->size),
514 (n == token) ? "<--" : "");
515 i++;
516 }
517}
518#else
519#define freelist_debug(_heap, _title, _token) do { } while (0)
520#endif
521
522static struct list_block *do_heap_free(struct nvmap_heap_block *block)
523{
524 struct list_block *b = container_of(block, struct list_block, block);
525 struct list_block *n = NULL;
526 struct nvmap_heap *heap = b->heap;
527
528 BUG_ON(b->block.base > b->orig_addr);
529 b->size += (b->block.base - b->orig_addr);
530 b->block.base = b->orig_addr;
531
532 freelist_debug(heap, "free list before", b);
533
534 /* Find position of first free block to the right of freed one */
535 list_for_each_entry(n, &heap->free_list, free_list) {
536 if (n->block.base > b->block.base)
537 break;
538 }
539
540 /* Add freed block before found free one */
541 list_add_tail(&b->free_list, &n->free_list);
542 BUG_ON(list_empty(&b->all_list));
543
544 freelist_debug(heap, "free list pre-merge", b);
545
546 /* merge freed block with next if they connect
547 * freed block becomes bigger, next one is destroyed */
548 if (!list_is_last(&b->free_list, &heap->free_list)) {
549 n = list_first_entry(&b->free_list, struct list_block, free_list);
550 if (n->block.base == b->block.base + b->size) {
551 list_del(&n->all_list);
552 list_del(&n->free_list);
553 BUG_ON(b->orig_addr >= n->orig_addr);
554 b->size += n->size;
555 kmem_cache_free(block_cache, n);
556 }
557 }
558
559 /* merge freed block with prev if they connect
560 * previous free block becomes bigger, freed one is destroyed */
561 if (b->free_list.prev != &heap->free_list) {
562 n = list_entry(b->free_list.prev, struct list_block, free_list);
563 if (n->block.base + n->size == b->block.base) {
564 list_del(&b->all_list);
565 list_del(&b->free_list);
566 BUG_ON(n->orig_addr >= b->orig_addr);
567 n->size += b->size;
568 kmem_cache_free(block_cache, b);
569 b = n;
570 }
571 }
572
573 freelist_debug(heap, "free list after", b);
574 b->block.type = BLOCK_EMPTY;
575 return b;
576}
577
578#ifndef CONFIG_NVMAP_CARVEOUT_COMPACTOR
579
580static struct nvmap_heap_block *do_buddy_alloc(struct nvmap_heap *h,
581 size_t len, size_t align,
582 unsigned int mem_prot)
583{
584 struct buddy_heap *bh;
585 struct nvmap_heap_block *b = NULL;
586
587 list_for_each_entry(bh, &h->buddy_list, buddy_list) {
588 b = buddy_alloc(bh, len, align, mem_prot);
589 if (b)
590 return b;
591 }
592
593 /* no buddy heaps could service this allocation: try to create a new
594 * buddy heap instead */
595 bh = kmem_cache_zalloc(buddy_heap_cache, GFP_KERNEL);
596 if (!bh)
597 return NULL;
598
599 b = do_heap_alloc(h, h->buddy_heap_size,
600 h->buddy_heap_size, mem_prot, 0);
601 if (!b) {
602 kmem_cache_free(buddy_heap_cache, bh);
603 return NULL;
604 }
605
606 bh->heap_base = container_of(b, struct list_block, block);
607 bh->nr_buddies = h->buddy_heap_size >> h->min_buddy_shift;
608 bh->bitmap[0].alloc = 0;
609 bh->bitmap[0].order = order_of(h->buddy_heap_size, h->min_buddy_shift);
610 list_add_tail(&bh->buddy_list, &h->buddy_list);
611 return buddy_alloc(bh, len, align, mem_prot);
612}
613
614#endif
615
616#ifdef CONFIG_NVMAP_CARVEOUT_COMPACTOR
617
618static int do_heap_copy_listblock(struct nvmap_device *dev,
619 unsigned long dst_base, unsigned long src_base, size_t len)
620{
621 pte_t **pte_src = NULL;
622 pte_t **pte_dst = NULL;
623 void *addr_src = NULL;
624 void *addr_dst = NULL;
625 unsigned long kaddr_src;
626 unsigned long kaddr_dst;
627 unsigned long phys_src = src_base;
628 unsigned long phys_dst = dst_base;
629 unsigned long pfn_src;
630 unsigned long pfn_dst;
631 int error = 0;
632
633 pgprot_t prot = pgprot_writecombine(pgprot_kernel);
634
635 int page;
636
637 pte_src = nvmap_alloc_pte(dev, &addr_src);
638 if (IS_ERR(pte_src)) {
639 pr_err("Error when allocating pte_src\n");
640 pte_src = NULL;
641 error = -1;
642 goto fail;
643 }
644
645 pte_dst = nvmap_alloc_pte(dev, &addr_dst);
646 if (IS_ERR(pte_dst)) {
647 pr_err("Error while allocating pte_dst\n");
648 pte_dst = NULL;
649 error = -1;
650 goto fail;
651 }
652
653 kaddr_src = (unsigned long)addr_src;
654 kaddr_dst = (unsigned long)addr_dst;
655
656 BUG_ON(phys_dst > phys_src);
657 BUG_ON((phys_src & PAGE_MASK) != phys_src);
658 BUG_ON((phys_dst & PAGE_MASK) != phys_dst);
659 BUG_ON((len & PAGE_MASK) != len);
660
661 for (page = 0; page < (len >> PAGE_SHIFT) ; page++) {
662
663 pfn_src = __phys_to_pfn(phys_src) + page;
664 pfn_dst = __phys_to_pfn(phys_dst) + page;
665
666 set_pte_at(&init_mm, kaddr_src, *pte_src,
667 pfn_pte(pfn_src, prot));
668 flush_tlb_kernel_page(kaddr_src);
669
670 set_pte_at(&init_mm, kaddr_dst, *pte_dst,
671 pfn_pte(pfn_dst, prot));
672 flush_tlb_kernel_page(kaddr_dst);
673
674 memcpy(addr_dst, addr_src, PAGE_SIZE);
675 }
676
677fail:
678 if (pte_src)
679 nvmap_free_pte(dev, pte_src);
680 if (pte_dst)
681 nvmap_free_pte(dev, pte_dst);
682 return error;
683}
684
685
686static struct nvmap_heap_block *do_heap_relocate_listblock(
687 struct list_block *block, bool fast)
688{
689 struct nvmap_heap_block *heap_block = &block->block;
690 struct nvmap_heap_block *heap_block_new = NULL;
691 struct nvmap_heap *heap = block->heap;
692 struct nvmap_handle *handle = heap_block->handle;
693 unsigned long src_base = heap_block->base;
694 unsigned long dst_base;
695 size_t src_size = block->size;
696 size_t src_align = block->align;
697 unsigned int src_prot = block->mem_prot;
698 int error = 0;
699 struct nvmap_share *share;
700
701 if (!handle) {
702 pr_err("INVALID HANDLE!\n");
703 return NULL;
704 }
705
706 mutex_lock(&handle->lock);
707
708 share = nvmap_get_share_from_dev(handle->dev);
709
710 /* TODO: It is possible to use only handle lock and no share
711 * pin_lock, but then we'll need to lock every handle during
712 * each pinning operation. Need to estimate performance impact
713 * if we decide to simplify locking this way. */
714 mutex_lock(&share->pin_lock);
715
716 /* abort if block is pinned */
717 if (atomic_read(&handle->pin))
718 goto fail;
719 /* abort if block is mapped */
720 if (handle->usecount)
721 goto fail;
722
723 if (fast) {
724 /* Fast compaction path - first allocate, then free. */
725 heap_block_new = do_heap_alloc(heap, src_size, src_align,
726 src_prot, src_base);
727 if (heap_block_new)
728 do_heap_free(heap_block);
729 else
730 goto fail;
731 } else {
732 /* Full compaction path, first free, then allocate
733 * It is slower but provide best compaction results */
734 do_heap_free(heap_block);
735 heap_block_new = do_heap_alloc(heap, src_size, src_align,
736 src_prot, src_base);
737 /* Allocation should always succeed*/
738 BUG_ON(!heap_block_new);
739 }
740
741 /* update handle */
742 handle->carveout = heap_block_new;
743 heap_block_new->handle = handle;
744
745 /* copy source data to new block location */
746 dst_base = heap_block_new->base;
747
748 /* new allocation should always go lower addresses */
749 BUG_ON(dst_base >= src_base);
750
751 error = do_heap_copy_listblock(handle->dev,
752 dst_base, src_base, src_size);
753 BUG_ON(error);
754
755fail:
756 mutex_unlock(&share->pin_lock);
757 mutex_unlock(&handle->lock);
758 return heap_block_new;
759}
760
761static void nvmap_heap_compact(struct nvmap_heap *heap,
762 size_t requested_size, bool fast)
763{
764 struct list_block *block_current = NULL;
765 struct list_block *block_prev = NULL;
766 struct list_block *block_next = NULL;
767
768 struct list_head *ptr, *ptr_prev, *ptr_next;
769 int relocation_count = 0;
770
771 ptr = heap->all_list.next;
772
773 /* walk through all blocks */
774 while (ptr != &heap->all_list) {
775 block_current = list_entry(ptr, struct list_block, all_list);
776
777 ptr_prev = ptr->prev;
778 ptr_next = ptr->next;
779
780 if (block_current->block.type != BLOCK_EMPTY) {
781 ptr = ptr_next;
782 continue;
783 }
784
785 if (fast && block_current->size >= requested_size)
786 break;
787
788 /* relocate prev block */
789 if (ptr_prev != &heap->all_list) {
790
791 block_prev = list_entry(ptr_prev,
792 struct list_block, all_list);
793
794 BUG_ON(block_prev->block.type != BLOCK_FIRST_FIT);
795
796 if (do_heap_relocate_listblock(block_prev, true)) {
797
798 /* After relocation current free block can be
799 * destroyed when it is merged with previous
800 * free block. Updated pointer to new free
801 * block can be obtained from the next block */
802 relocation_count++;
803 ptr = ptr_next->prev;
804 continue;
805 }
806 }
807
808 if (ptr_next != &heap->all_list) {
809
810 block_next = list_entry(ptr_next,
811 struct list_block, all_list);
812
813 BUG_ON(block_next->block.type != BLOCK_FIRST_FIT);
814
815 if (do_heap_relocate_listblock(block_next, fast)) {
816 ptr = ptr_prev->next;
817 relocation_count++;
818 continue;
819 }
820 }
821 ptr = ptr_next;
822 }
823 pr_err("Relocated %d chunks\n", relocation_count);
824}
825#endif
826
827void nvmap_usecount_inc(struct nvmap_handle *h)
828{
829 if (h->alloc && !h->heap_pgalloc) {
830 mutex_lock(&h->lock);
831 h->usecount++;
832 mutex_unlock(&h->lock);
833 } else {
834 h->usecount++;
835 }
836}
837
838
839void nvmap_usecount_dec(struct nvmap_handle *h)
840{
841 h->usecount--;
842}
843
844/* nvmap_heap_alloc: allocates a block of memory of len bytes, aligned to
845 * align bytes. */
846struct nvmap_heap_block *nvmap_heap_alloc(struct nvmap_heap *h,
847 struct nvmap_handle *handle)
848{
849 struct nvmap_heap_block *b;
850 size_t len = handle->size;
851 size_t align = handle->align;
852 unsigned int prot = handle->flags;
853
854 mutex_lock(&h->lock);
855
856#ifdef CONFIG_NVMAP_CARVEOUT_COMPACTOR
857 /* Align to page size */
858 align = ALIGN(align, PAGE_SIZE);
859 len = ALIGN(len, PAGE_SIZE);
860 b = do_heap_alloc(h, len, align, prot, 0);
861 if (!b) {
862 pr_err("Compaction triggered!\n");
863 nvmap_heap_compact(h, len, true);
864 b = do_heap_alloc(h, len, align, prot, 0);
865 if (!b) {
866 pr_err("Full compaction triggered!\n");
867 nvmap_heap_compact(h, len, false);
868 b = do_heap_alloc(h, len, align, prot, 0);
869 }
870 }
871#else
872 if (len <= h->buddy_heap_size / 2) {
873 b = do_buddy_alloc(h, len, align, prot);
874 } else {
875 if (h->buddy_heap_size)
876 len = ALIGN(len, h->buddy_heap_size);
877 align = max(align, (size_t)L1_CACHE_BYTES);
878 b = do_heap_alloc(h, len, align, prot, 0);
879 }
880#endif
881
882 if (b) {
883 b->handle = handle;
884 handle->carveout = b;
885 }
886 mutex_unlock(&h->lock);
887 return b;
888}
889
890struct nvmap_heap *nvmap_block_to_heap(struct nvmap_heap_block *b)
891{
892 if (b->type == BLOCK_BUDDY) {
893 struct buddy_block *bb;
894 bb = container_of(b, struct buddy_block, block);
895 return parent_of(bb->heap);
896 } else {
897 struct list_block *lb;
898 lb = container_of(b, struct list_block, block);
899 return lb->heap;
900 }
901}
902
903/* nvmap_heap_free: frees block b*/
904void nvmap_heap_free(struct nvmap_heap_block *b)
905{
906 struct buddy_heap *bh = NULL;
907 struct nvmap_heap *h = nvmap_block_to_heap(b);
908 struct list_block *lb;
909
910 mutex_lock(&h->lock);
911 if (b->type == BLOCK_BUDDY)
912 bh = do_buddy_free(b);
913 else {
914 lb = container_of(b, struct list_block, block);
915 nvmap_flush_heap_block(NULL, b, lb->size, lb->mem_prot);
916 do_heap_free(b);
917 }
918
919 if (bh) {
920 list_del(&bh->buddy_list);
921 mutex_unlock(&h->lock);
922 nvmap_heap_free(&bh->heap_base->block);
923 kmem_cache_free(buddy_heap_cache, bh);
924 } else
925 mutex_unlock(&h->lock);
926}
927
928
929static void heap_release(struct device *heap)
930{
931}
932
933/* nvmap_heap_create: create a heap object of len bytes, starting from
934 * address base.
935 *
936 * if buddy_size is >= NVMAP_HEAP_MIN_BUDDY_SIZE, then allocations <= 1/2
937 * of the buddy heap size will use a buddy sub-allocator, where each buddy
938 * heap is buddy_size bytes (should be a power of 2). all other allocations
939 * will be rounded up to be a multiple of buddy_size bytes.
940 */
941struct nvmap_heap *nvmap_heap_create(struct device *parent, const char *name,
942 phys_addr_t base, size_t len,
943 size_t buddy_size, void *arg)
944{
945 struct nvmap_heap *h = NULL;
946 struct list_block *l = NULL;
947
948 if (WARN_ON(buddy_size && buddy_size < NVMAP_HEAP_MIN_BUDDY_SIZE)) {
949 dev_warn(parent, "%s: buddy_size %u too small\n", __func__,
950 buddy_size);
951 buddy_size = 0;
952 } else if (WARN_ON(buddy_size >= len)) {
953 dev_warn(parent, "%s: buddy_size %u too large\n", __func__,
954 buddy_size);
955 buddy_size = 0;
956 } else if (WARN_ON(buddy_size & (buddy_size - 1))) {
957 dev_warn(parent, "%s: buddy_size %u not a power of 2\n",
958 __func__, buddy_size);
959 buddy_size = 1 << (ilog2(buddy_size) + 1);
960 }
961
962 if (WARN_ON(buddy_size && (base & (buddy_size - 1)))) {
963 unsigned long orig = base;
964 dev_warn(parent, "%s: base address %p not aligned to "
965 "buddy_size %u\n", __func__, (void *)base, buddy_size);
966 base = ALIGN(base, buddy_size);
967 len -= (base - orig);
968 }
969
970 if (WARN_ON(buddy_size && (len & (buddy_size - 1)))) {
971 dev_warn(parent, "%s: length %u not aligned to "
972 "buddy_size %u\n", __func__, len, buddy_size);
973 len &= ~(buddy_size - 1);
974 }
975
976 h = kzalloc(sizeof(*h), GFP_KERNEL);
977 if (!h) {
978 dev_err(parent, "%s: out of memory\n", __func__);
979 goto fail_alloc;
980 }
981
982 l = kmem_cache_zalloc(block_cache, GFP_KERNEL);
983 if (!l) {
984 dev_err(parent, "%s: out of memory\n", __func__);
985 goto fail_alloc;
986 }
987
988 dev_set_name(&h->dev, "heap-%s", name);
989 h->name = name;
990 h->arg = arg;
991 h->dev.parent = parent;
992 h->dev.driver = NULL;
993 h->dev.release = heap_release;
994 if (device_register(&h->dev)) {
995 dev_err(parent, "%s: failed to register %s\n", __func__,
996 dev_name(&h->dev));
997 goto fail_alloc;
998 }
999 if (sysfs_create_group(&h->dev.kobj, &heap_stat_attr_group)) {
1000 dev_err(&h->dev, "%s: failed to create attributes\n", __func__);
1001 goto fail_register;
1002 }
1003 h->small_alloc = max(2 * buddy_size, len / 256);
1004 h->buddy_heap_size = buddy_size;
1005 if (buddy_size)
1006 h->min_buddy_shift = ilog2(buddy_size / MAX_BUDDY_NR);
1007 INIT_LIST_HEAD(&h->free_list);
1008 INIT_LIST_HEAD(&h->buddy_list);
1009 INIT_LIST_HEAD(&h->all_list);
1010 mutex_init(&h->lock);
1011 l->block.base = base;
1012 l->block.type = BLOCK_EMPTY;
1013 l->size = len;
1014 l->orig_addr = base;
1015 list_add_tail(&l->free_list, &h->free_list);
1016 list_add_tail(&l->all_list, &h->all_list);
1017
1018 inner_flush_cache_all();
1019 outer_flush_range(base, base + len);
1020 wmb();
1021 return h;
1022
1023fail_register:
1024 device_unregister(&h->dev);
1025fail_alloc:
1026 if (l)
1027 kmem_cache_free(block_cache, l);
1028 kfree(h);
1029 return NULL;
1030}
1031
1032void *nvmap_heap_device_to_arg(struct device *dev)
1033{
1034 struct nvmap_heap *heap = container_of(dev, struct nvmap_heap, dev);
1035 return heap->arg;
1036}
1037
1038void *nvmap_heap_to_arg(struct nvmap_heap *heap)
1039{
1040 return heap->arg;
1041}
1042
1043/* nvmap_heap_destroy: frees all resources in heap */
1044void nvmap_heap_destroy(struct nvmap_heap *heap)
1045{
1046 WARN_ON(!list_empty(&heap->buddy_list));
1047
1048 sysfs_remove_group(&heap->dev.kobj, &heap_stat_attr_group);
1049 device_unregister(&heap->dev);
1050
1051 while (!list_empty(&heap->buddy_list)) {
1052 struct buddy_heap *b;
1053 b = list_first_entry(&heap->buddy_list, struct buddy_heap,
1054 buddy_list);
1055 list_del(&heap->buddy_list);
1056 nvmap_heap_free(&b->heap_base->block);
1057 kmem_cache_free(buddy_heap_cache, b);
1058 }
1059
1060 WARN_ON(!list_is_singular(&heap->all_list));
1061 while (!list_empty(&heap->all_list)) {
1062 struct list_block *l;
1063 l = list_first_entry(&heap->all_list, struct list_block,
1064 all_list);
1065 list_del(&l->all_list);
1066 kmem_cache_free(block_cache, l);
1067 }
1068
1069 kfree(heap);
1070}
1071
1072/* nvmap_heap_create_group: adds the attribute_group grp to the heap kobject */
1073int nvmap_heap_create_group(struct nvmap_heap *heap,
1074 const struct attribute_group *grp)
1075{
1076 return sysfs_create_group(&heap->dev.kobj, grp);
1077}
1078
1079/* nvmap_heap_remove_group: removes the attribute_group grp */
1080void nvmap_heap_remove_group(struct nvmap_heap *heap,
1081 const struct attribute_group *grp)
1082{
1083 sysfs_remove_group(&heap->dev.kobj, grp);
1084}
1085
1086int nvmap_heap_init(void)
1087{
1088 BUG_ON(buddy_heap_cache != NULL);
1089 buddy_heap_cache = KMEM_CACHE(buddy_heap, 0);
1090 if (!buddy_heap_cache) {
1091 pr_err("%s: unable to create buddy heap cache\n", __func__);
1092 return -ENOMEM;
1093 }
1094
1095 block_cache = KMEM_CACHE(combo_block, 0);
1096 if (!block_cache) {
1097 kmem_cache_destroy(buddy_heap_cache);
1098 pr_err("%s: unable to create block cache\n", __func__);
1099 return -ENOMEM;
1100 }
1101 return 0;
1102}
1103
1104void nvmap_heap_deinit(void)
1105{
1106 if (buddy_heap_cache)
1107 kmem_cache_destroy(buddy_heap_cache);
1108 if (block_cache)
1109 kmem_cache_destroy(block_cache);
1110
1111 block_cache = NULL;
1112 buddy_heap_cache = NULL;
1113}
diff --git a/drivers/video/tegra/nvmap/nvmap_heap.h b/drivers/video/tegra/nvmap/nvmap_heap.h
new file mode 100644
index 00000000000..158a1fa3d33
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_heap.h
@@ -0,0 +1,68 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_heap.h
3 *
4 * GPU heap allocator.
5 *
6 * Copyright (c) 2010-2011, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef __NVMAP_HEAP_H
24#define __NVMAP_HEAP_H
25
26struct device;
27struct nvmap_heap;
28struct attribute_group;
29
30struct nvmap_heap_block {
31 phys_addr_t base;
32 unsigned int type;
33 struct nvmap_handle *handle;
34};
35
36#define NVMAP_HEAP_MIN_BUDDY_SIZE 8192
37
38struct nvmap_heap *nvmap_heap_create(struct device *parent, const char *name,
39 phys_addr_t base, size_t len,
40 unsigned int buddy_size, void *arg);
41
42void nvmap_heap_destroy(struct nvmap_heap *heap);
43
44void *nvmap_heap_device_to_arg(struct device *dev);
45
46void *nvmap_heap_to_arg(struct nvmap_heap *heap);
47
48struct nvmap_heap_block *nvmap_heap_alloc(struct nvmap_heap *heap,
49 struct nvmap_handle *handle);
50
51struct nvmap_heap *nvmap_block_to_heap(struct nvmap_heap_block *b);
52
53void nvmap_heap_free(struct nvmap_heap_block *block);
54
55int nvmap_heap_create_group(struct nvmap_heap *heap,
56 const struct attribute_group *grp);
57
58void nvmap_heap_remove_group(struct nvmap_heap *heap,
59 const struct attribute_group *grp);
60
61int __init nvmap_heap_init(void);
62
63void nvmap_heap_deinit(void);
64
65int nvmap_flush_heap_block(struct nvmap_client *client,
66 struct nvmap_heap_block *block, size_t len, unsigned int prot);
67
68#endif
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.c b/drivers/video/tegra/nvmap/nvmap_ioctl.c
new file mode 100644
index 00000000000..58bc71d5046
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.c
@@ -0,0 +1,749 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_ioctl.c
3 *
4 * User-space interface to nvmap
5 *
6 * Copyright (c) 2011, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/dma-mapping.h>
24#include <linux/fs.h>
25#include <linux/kernel.h>
26#include <linux/slab.h>
27#include <linux/uaccess.h>
28
29#include <asm/cacheflush.h>
30#include <asm/outercache.h>
31#include <asm/tlbflush.h>
32
33#include <mach/iovmm.h>
34#include <mach/nvmap.h>
35
36#include "nvmap_ioctl.h"
37#include "nvmap.h"
38#include "nvmap_common.h"
39
40static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h,
41 int is_read, unsigned long h_offs,
42 unsigned long sys_addr, unsigned long h_stride,
43 unsigned long sys_stride, unsigned long elem_size,
44 unsigned long count);
45
46static int cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
47 unsigned long start, unsigned long end, unsigned int op);
48
49
50int nvmap_ioctl_pinop(struct file *filp, bool is_pin, void __user *arg)
51{
52 struct nvmap_pin_handle op;
53 struct nvmap_handle *h;
54 unsigned long on_stack[16];
55 unsigned long *refs;
56 unsigned long __user *output;
57 unsigned int i;
58 int err = 0;
59
60 if (copy_from_user(&op, arg, sizeof(op)))
61 return -EFAULT;
62
63 if (!op.count)
64 return -EINVAL;
65
66 if (op.count > 1) {
67 size_t bytes = op.count * sizeof(unsigned long *);
68
69 if (op.count > ARRAY_SIZE(on_stack))
70 refs = kmalloc(op.count * sizeof(*refs), GFP_KERNEL);
71 else
72 refs = on_stack;
73
74 if (!refs)
75 return -ENOMEM;
76
77 if (copy_from_user(refs, (void *)op.handles, bytes)) {
78 err = -EFAULT;
79 goto out;
80 }
81 } else {
82 refs = on_stack;
83 on_stack[0] = (unsigned long)op.handles;
84 }
85
86 if (is_pin)
87 err = nvmap_pin_ids(filp->private_data, op.count, refs);
88 else
89 nvmap_unpin_ids(filp->private_data, op.count, refs);
90
91 /* skip the output stage on unpin */
92 if (err || !is_pin)
93 goto out;
94
95 /* it is guaranteed that if nvmap_pin_ids returns 0 that
96 * all of the handle_ref objects are valid, so dereferencing
97 * directly here is safe */
98 if (op.count > 1)
99 output = (unsigned long __user *)op.addr;
100 else {
101 struct nvmap_pin_handle __user *tmp = arg;
102 output = (unsigned long __user *)&(tmp->addr);
103 }
104
105 if (!output)
106 goto out;
107
108 for (i = 0; i < op.count && !err; i++) {
109 unsigned long addr;
110
111 h = (struct nvmap_handle *)refs[i];
112
113 if (h->heap_pgalloc && h->pgalloc.contig)
114 addr = page_to_phys(h->pgalloc.pages[0]);
115 else if (h->heap_pgalloc)
116 addr = h->pgalloc.area->iovm_start;
117 else
118 addr = h->carveout->base;
119
120 err = put_user(addr, &output[i]);
121 }
122
123 if (err)
124 nvmap_unpin_ids(filp->private_data, op.count, refs);
125
126out:
127 if (refs != on_stack)
128 kfree(refs);
129
130 return err;
131}
132
133int nvmap_ioctl_getid(struct file *filp, void __user *arg)
134{
135 struct nvmap_client *client = filp->private_data;
136 struct nvmap_create_handle op;
137 struct nvmap_handle *h = NULL;
138
139 if (copy_from_user(&op, arg, sizeof(op)))
140 return -EFAULT;
141
142 if (!op.handle)
143 return -EINVAL;
144
145 h = nvmap_get_handle_id(client, op.handle);
146
147 if (!h)
148 return -EPERM;
149
150 op.id = (__u32)h;
151 if (client == h->owner)
152 h->global = true;
153
154 nvmap_handle_put(h);
155
156 return copy_to_user(arg, &op, sizeof(op)) ? -EFAULT : 0;
157}
158
159int nvmap_ioctl_alloc(struct file *filp, void __user *arg)
160{
161 struct nvmap_alloc_handle op;
162 struct nvmap_client *client = filp->private_data;
163
164 if (copy_from_user(&op, arg, sizeof(op)))
165 return -EFAULT;
166
167 if (!op.handle)
168 return -EINVAL;
169
170 if (op.align & (op.align - 1))
171 return -EINVAL;
172
173 /* user-space handles are aligned to page boundaries, to prevent
174 * data leakage. */
175 op.align = max_t(size_t, op.align, PAGE_SIZE);
176
177 return nvmap_alloc_handle_id(client, op.handle, op.heap_mask,
178 op.align, op.flags);
179}
180
181int nvmap_ioctl_create(struct file *filp, unsigned int cmd, void __user *arg)
182{
183 struct nvmap_create_handle op;
184 struct nvmap_handle_ref *ref = NULL;
185 struct nvmap_client *client = filp->private_data;
186 int err = 0;
187
188 if (copy_from_user(&op, arg, sizeof(op)))
189 return -EFAULT;
190
191 if (!client)
192 return -ENODEV;
193
194 if (cmd == NVMAP_IOC_CREATE) {
195 ref = nvmap_create_handle(client, PAGE_ALIGN(op.size));
196 if (!IS_ERR(ref))
197 ref->handle->orig_size = op.size;
198 } else if (cmd == NVMAP_IOC_FROM_ID) {
199 ref = nvmap_duplicate_handle_id(client, op.id);
200 } else {
201 return -EINVAL;
202 }
203
204 if (IS_ERR(ref))
205 return PTR_ERR(ref);
206
207 op.handle = nvmap_ref_to_id(ref);
208 if (copy_to_user(arg, &op, sizeof(op))) {
209 err = -EFAULT;
210 nvmap_free_handle_id(client, op.handle);
211 }
212
213 return err;
214}
215
216int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg)
217{
218 struct nvmap_client *client = filp->private_data;
219 struct nvmap_map_caller op;
220 struct nvmap_vma_priv *vpriv;
221 struct vm_area_struct *vma;
222 struct nvmap_handle *h = NULL;
223 unsigned int cache_flags;
224 int err = 0;
225
226 if (copy_from_user(&op, arg, sizeof(op)))
227 return -EFAULT;
228
229 if (!op.handle)
230 return -EINVAL;
231
232 h = nvmap_get_handle_id(client, op.handle);
233
234 if (!h)
235 return -EPERM;
236
237 down_read(&current->mm->mmap_sem);
238
239 vma = find_vma(current->mm, op.addr);
240 if (!vma || !vma->vm_private_data) {
241 err = -ENOMEM;
242 goto out;
243 }
244
245 if (op.offset & ~PAGE_MASK) {
246 err = -EFAULT;
247 goto out;
248 }
249
250 if ((op.offset + op.length) > h->size) {
251 err = -EADDRNOTAVAIL;
252 goto out;
253 }
254
255 vpriv = vma->vm_private_data;
256 BUG_ON(!vpriv);
257
258 /* the VMA must exactly match the requested mapping operation, and the
259 * VMA that is targetted must have been created by this driver
260 */
261 if ((vma->vm_start != op.addr) || !is_nvmap_vma(vma) ||
262 (vma->vm_end-vma->vm_start != op.length)) {
263 err = -EPERM;
264 goto out;
265 }
266
267 /* verify that each mmap() system call creates a unique VMA */
268
269 if (vpriv->handle && (h == vpriv->handle)) {
270 goto out;
271 } else if (vpriv->handle) {
272 err = -EADDRNOTAVAIL;
273 goto out;
274 }
275
276 nvmap_usecount_inc(h);
277
278 if (!h->heap_pgalloc && (h->carveout->base & ~PAGE_MASK)) {
279 nvmap_usecount_dec(h);
280 err = -EFAULT;
281 goto out;
282 }
283
284 vpriv->handle = h;
285 vpriv->offs = op.offset;
286
287 cache_flags = op.flags & NVMAP_HANDLE_CACHE_FLAG;
288 if ((cache_flags == NVMAP_HANDLE_INNER_CACHEABLE ||
289 cache_flags == NVMAP_HANDLE_CACHEABLE) &&
290 (h->flags == NVMAP_HANDLE_UNCACHEABLE ||
291 h->flags == NVMAP_HANDLE_WRITE_COMBINE)) {
292 if (h->size & ~PAGE_MASK) {
293 pr_err("\n%s:attempt to convert a buffer from uc/wc to"
294 " wb, whose size is not a multiple of page size."
295 " request ignored.\n", __func__);
296 } else {
297 unsigned int nr_page = h->size >> PAGE_SHIFT;
298 wmb();
299 /* override allocation time cache coherency attributes. */
300 h->flags &= ~NVMAP_HANDLE_CACHE_FLAG;
301 h->flags |= cache_flags;
302
303 /* Update page attributes, if the memory is allocated
304 * from system heap pages.
305 */
306 if (cache_flags == NVMAP_HANDLE_INNER_CACHEABLE &&
307 h->heap_pgalloc)
308 set_pages_array_iwb(h->pgalloc.pages, nr_page);
309 else if (h->heap_pgalloc)
310 set_pages_array_wb(h->pgalloc.pages, nr_page);
311 }
312 }
313 vma->vm_page_prot = nvmap_pgprot(h, vma->vm_page_prot);
314
315out:
316 up_read(&current->mm->mmap_sem);
317
318 if (err)
319 nvmap_handle_put(h);
320 return err;
321}
322
323int nvmap_ioctl_get_param(struct file *filp, void __user* arg)
324{
325 struct nvmap_handle_param op;
326 struct nvmap_client *client = filp->private_data;
327 struct nvmap_handle *h;
328 int err = 0;
329
330 if (copy_from_user(&op, arg, sizeof(op)))
331 return -EFAULT;
332
333 h = nvmap_get_handle_id(client, op.handle);
334 if (!h)
335 return -EINVAL;
336
337 switch (op.param) {
338 case NVMAP_HANDLE_PARAM_SIZE:
339 op.result = h->orig_size;
340 break;
341 case NVMAP_HANDLE_PARAM_ALIGNMENT:
342 mutex_lock(&h->lock);
343 if (!h->alloc)
344 op.result = 0;
345 else if (h->heap_pgalloc)
346 op.result = PAGE_SIZE;
347 else if (h->carveout->base)
348 op.result = (h->carveout->base & -h->carveout->base);
349 else
350 op.result = SZ_4M;
351 mutex_unlock(&h->lock);
352 break;
353 case NVMAP_HANDLE_PARAM_BASE:
354 if (WARN_ON(!h->alloc || !atomic_add_return(0, &h->pin)))
355 op.result = -1ul;
356 else if (!h->heap_pgalloc) {
357 mutex_lock(&h->lock);
358 op.result = h->carveout->base;
359 mutex_unlock(&h->lock);
360 } else if (h->pgalloc.contig)
361 op.result = page_to_phys(h->pgalloc.pages[0]);
362 else if (h->pgalloc.area)
363 op.result = h->pgalloc.area->iovm_start;
364 else
365 op.result = -1ul;
366 break;
367 case NVMAP_HANDLE_PARAM_HEAP:
368 if (!h->alloc)
369 op.result = 0;
370 else if (!h->heap_pgalloc) {
371 mutex_lock(&h->lock);
372 op.result = nvmap_carveout_usage(client, h->carveout);
373 mutex_unlock(&h->lock);
374 } else if (h->pgalloc.contig)
375 op.result = NVMAP_HEAP_SYSMEM;
376 else
377 op.result = NVMAP_HEAP_IOVMM;
378 break;
379 default:
380 err = -EINVAL;
381 break;
382 }
383
384 if (!err && copy_to_user(arg, &op, sizeof(op)))
385 err = -EFAULT;
386
387 nvmap_handle_put(h);
388 return err;
389}
390
391int nvmap_ioctl_rw_handle(struct file *filp, int is_read, void __user* arg)
392{
393 struct nvmap_client *client = filp->private_data;
394 struct nvmap_rw_handle __user *uarg = arg;
395 struct nvmap_rw_handle op;
396 struct nvmap_handle *h;
397 ssize_t copied;
398 int err = 0;
399
400 if (copy_from_user(&op, arg, sizeof(op)))
401 return -EFAULT;
402
403 if (!op.handle || !op.addr || !op.count || !op.elem_size)
404 return -EINVAL;
405
406 h = nvmap_get_handle_id(client, op.handle);
407 if (!h)
408 return -EPERM;
409
410 nvmap_usecount_inc(h);
411
412 copied = rw_handle(client, h, is_read, op.offset,
413 (unsigned long)op.addr, op.hmem_stride,
414 op.user_stride, op.elem_size, op.count);
415
416 if (copied < 0) {
417 err = copied;
418 copied = 0;
419 } else if (copied < (op.count * op.elem_size))
420 err = -EINTR;
421
422 __put_user(copied, &uarg->count);
423
424 nvmap_usecount_dec(h);
425
426 nvmap_handle_put(h);
427
428 return err;
429}
430
431int nvmap_ioctl_cache_maint(struct file *filp, void __user *arg)
432{
433 struct nvmap_client *client = filp->private_data;
434 struct nvmap_cache_op op;
435 struct vm_area_struct *vma;
436 struct nvmap_vma_priv *vpriv;
437 unsigned long start;
438 unsigned long end;
439 int err = 0;
440
441 if (copy_from_user(&op, arg, sizeof(op)))
442 return -EFAULT;
443
444 if (!op.handle || !op.addr || op.op < NVMAP_CACHE_OP_WB ||
445 op.op > NVMAP_CACHE_OP_WB_INV)
446 return -EINVAL;
447
448 down_read(&current->mm->mmap_sem);
449
450 vma = find_vma(current->active_mm, (unsigned long)op.addr);
451 if (!vma || !is_nvmap_vma(vma) ||
452 (unsigned long)op.addr + op.len > vma->vm_end) {
453 err = -EADDRNOTAVAIL;
454 goto out;
455 }
456
457 vpriv = (struct nvmap_vma_priv *)vma->vm_private_data;
458
459 if ((unsigned long)vpriv->handle != op.handle) {
460 err = -EFAULT;
461 goto out;
462 }
463
464 start = (unsigned long)op.addr - vma->vm_start;
465 end = start + op.len;
466
467 err = cache_maint(client, vpriv->handle, start, end, op.op);
468out:
469 up_read(&current->mm->mmap_sem);
470 return err;
471}
472
473int nvmap_ioctl_free(struct file *filp, unsigned long arg)
474{
475 struct nvmap_client *client = filp->private_data;
476
477 if (!arg)
478 return 0;
479
480 nvmap_free_handle_id(client, arg);
481 return 0;
482}
483
484static void inner_cache_maint(unsigned int op, void *vaddr, size_t size)
485{
486 if (op == NVMAP_CACHE_OP_WB_INV)
487 dmac_flush_range(vaddr, vaddr + size);
488 else if (op == NVMAP_CACHE_OP_INV)
489 dmac_map_area(vaddr, size, DMA_FROM_DEVICE);
490 else
491 dmac_map_area(vaddr, size, DMA_TO_DEVICE);
492}
493
494static void outer_cache_maint(unsigned int op, unsigned long paddr, size_t size)
495{
496 if (op == NVMAP_CACHE_OP_WB_INV)
497 outer_flush_range(paddr, paddr + size);
498 else if (op == NVMAP_CACHE_OP_INV)
499 outer_inv_range(paddr, paddr + size);
500 else
501 outer_clean_range(paddr, paddr + size);
502}
503
504static void heap_page_cache_maint(struct nvmap_client *client,
505 struct nvmap_handle *h, unsigned long start, unsigned long end,
506 unsigned int op, bool inner, bool outer, pte_t **pte,
507 unsigned long kaddr, pgprot_t prot)
508{
509 struct page *page;
510 unsigned long paddr;
511 unsigned long next;
512 unsigned long off;
513 size_t size;
514
515 while (start < end) {
516 page = h->pgalloc.pages[start >> PAGE_SHIFT];
517 next = min(((start + PAGE_SIZE) & PAGE_MASK), end);
518 off = start & ~PAGE_MASK;
519 size = next - start;
520 paddr = page_to_phys(page) + off;
521
522 if (inner) {
523 void *vaddr = (void *)kaddr + off;
524 BUG_ON(!pte);
525 BUG_ON(!kaddr);
526 set_pte_at(&init_mm, kaddr, *pte,
527 pfn_pte(__phys_to_pfn(paddr), prot));
528 flush_tlb_kernel_page(kaddr);
529 inner_cache_maint(op, vaddr, size);
530 }
531
532 if (outer)
533 outer_cache_maint(op, paddr, size);
534 start = next;
535 }
536}
537
538static bool fast_cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
539 unsigned long start, unsigned long end, unsigned int op)
540{
541 int ret = false;
542
543 if ((op == NVMAP_CACHE_OP_INV) ||
544 ((end - start) < FLUSH_CLEAN_BY_SET_WAY_THRESHOLD))
545 goto out;
546
547 if (op == NVMAP_CACHE_OP_WB_INV)
548 inner_flush_cache_all();
549 else if (op == NVMAP_CACHE_OP_WB)
550 inner_clean_cache_all();
551
552 if (h->heap_pgalloc && (h->flags != NVMAP_HANDLE_INNER_CACHEABLE)) {
553 heap_page_cache_maint(client, h, start, end, op,
554 false, true, NULL, 0, 0);
555 } else if (h->flags != NVMAP_HANDLE_INNER_CACHEABLE) {
556 start += h->carveout->base;
557 end += h->carveout->base;
558 outer_cache_maint(op, start, end - start);
559 }
560 ret = true;
561out:
562 return ret;
563}
564
565static int cache_maint(struct nvmap_client *client, struct nvmap_handle *h,
566 unsigned long start, unsigned long end, unsigned int op)
567{
568 pgprot_t prot;
569 pte_t **pte = NULL;
570 unsigned long kaddr;
571 unsigned long loop;
572 int err = 0;
573
574 h = nvmap_handle_get(h);
575 if (!h)
576 return -EFAULT;
577
578 if (!h->alloc) {
579 err = -EFAULT;
580 goto out;
581 }
582
583 wmb();
584 if (h->flags == NVMAP_HANDLE_UNCACHEABLE ||
585 h->flags == NVMAP_HANDLE_WRITE_COMBINE || start == end)
586 goto out;
587
588 if (fast_cache_maint(client, h, start, end, op))
589 goto out;
590
591 prot = nvmap_pgprot(h, pgprot_kernel);
592 pte = nvmap_alloc_pte(client->dev, (void **)&kaddr);
593 if (IS_ERR(pte)) {
594 err = PTR_ERR(pte);
595 pte = NULL;
596 goto out;
597 }
598
599 if (h->heap_pgalloc) {
600 heap_page_cache_maint(client, h, start, end, op, true,
601 (h->flags == NVMAP_HANDLE_INNER_CACHEABLE) ? false : true,
602 pte, kaddr, prot);
603 goto out;
604 }
605
606 if (start > h->size || end > h->size) {
607 nvmap_warn(client, "cache maintenance outside handle\n");
608 return -EINVAL;
609 }
610
611 /* lock carveout from relocation by mapcount */
612 nvmap_usecount_inc(h);
613
614 start += h->carveout->base;
615 end += h->carveout->base;
616
617 loop = start;
618
619 while (loop < end) {
620 unsigned long next = (loop + PAGE_SIZE) & PAGE_MASK;
621 void *base = (void *)kaddr + (loop & ~PAGE_MASK);
622 next = min(next, end);
623
624 set_pte_at(&init_mm, kaddr, *pte,
625 pfn_pte(__phys_to_pfn(loop), prot));
626 flush_tlb_kernel_page(kaddr);
627
628 inner_cache_maint(op, base, next - loop);
629 loop = next;
630 }
631
632 if (h->flags != NVMAP_HANDLE_INNER_CACHEABLE)
633 outer_cache_maint(op, start, end - start);
634
635 /* unlock carveout */
636 nvmap_usecount_dec(h);
637
638out:
639 if (pte)
640 nvmap_free_pte(client->dev, pte);
641 nvmap_handle_put(h);
642 return err;
643}
644
645static int rw_handle_page(struct nvmap_handle *h, int is_read,
646 phys_addr_t start, unsigned long rw_addr,
647 unsigned long bytes, unsigned long kaddr, pte_t *pte)
648{
649 pgprot_t prot = nvmap_pgprot(h, pgprot_kernel);
650 unsigned long end = start + bytes;
651 int err = 0;
652
653 while (!err && start < end) {
654 struct page *page = NULL;
655 phys_addr_t phys;
656 size_t count;
657 void *src;
658
659 if (!h->heap_pgalloc) {
660 phys = h->carveout->base + start;
661 } else {
662 page = h->pgalloc.pages[start >> PAGE_SHIFT];
663 BUG_ON(!page);
664 get_page(page);
665 phys = page_to_phys(page) + (start & ~PAGE_MASK);
666 }
667
668 set_pte_at(&init_mm, kaddr, pte,
669 pfn_pte(__phys_to_pfn(phys), prot));
670 flush_tlb_kernel_page(kaddr);
671
672 src = (void *)kaddr + (phys & ~PAGE_MASK);
673 phys = PAGE_SIZE - (phys & ~PAGE_MASK);
674 count = min_t(size_t, end - start, phys);
675
676 if (is_read)
677 err = copy_to_user((void *)rw_addr, src, count);
678 else
679 err = copy_from_user(src, (void *)rw_addr, count);
680
681 if (err)
682 err = -EFAULT;
683
684 rw_addr += count;
685 start += count;
686
687 if (page)
688 put_page(page);
689 }
690
691 return err;
692}
693
694static ssize_t rw_handle(struct nvmap_client *client, struct nvmap_handle *h,
695 int is_read, unsigned long h_offs,
696 unsigned long sys_addr, unsigned long h_stride,
697 unsigned long sys_stride, unsigned long elem_size,
698 unsigned long count)
699{
700 ssize_t copied = 0;
701 pte_t **pte;
702 void *addr;
703 int ret = 0;
704
705 if (!elem_size)
706 return -EINVAL;
707
708 if (!h->alloc)
709 return -EFAULT;
710
711 if (elem_size == h_stride && elem_size == sys_stride) {
712 elem_size *= count;
713 h_stride = elem_size;
714 sys_stride = elem_size;
715 count = 1;
716 }
717
718 pte = nvmap_alloc_pte(client->dev, &addr);
719 if (IS_ERR(pte))
720 return PTR_ERR(pte);
721
722 while (count--) {
723 if (h_offs + elem_size > h->size) {
724 nvmap_warn(client, "read/write outside of handle\n");
725 ret = -EFAULT;
726 break;
727 }
728 if (is_read)
729 cache_maint(client, h, h_offs,
730 h_offs + elem_size, NVMAP_CACHE_OP_INV);
731
732 ret = rw_handle_page(h, is_read, h_offs, sys_addr,
733 elem_size, (unsigned long)addr, *pte);
734
735 if (ret)
736 break;
737
738 if (!is_read)
739 cache_maint(client, h, h_offs,
740 h_offs + elem_size, NVMAP_CACHE_OP_WB);
741
742 copied += elem_size;
743 sys_addr += sys_stride;
744 h_offs += h_stride;
745 }
746
747 nvmap_free_pte(client->dev, pte);
748 return ret ?: copied;
749}
diff --git a/drivers/video/tegra/nvmap/nvmap_ioctl.h b/drivers/video/tegra/nvmap/nvmap_ioctl.h
new file mode 100644
index 00000000000..c802cd4dd7a
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_ioctl.h
@@ -0,0 +1,159 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_ioctl.h
3 *
4 * ioctl declarations for nvmap
5 *
6 * Copyright (c) 2010, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#ifndef __VIDEO_TEGRA_NVMAP_IOCTL_H
24#define __VIDEO_TEGRA_NVMAP_IOCTL_H
25
26#include <linux/ioctl.h>
27#include <linux/file.h>
28
29#include <mach/nvmap.h>
30
31enum {
32 NVMAP_HANDLE_PARAM_SIZE = 1,
33 NVMAP_HANDLE_PARAM_ALIGNMENT,
34 NVMAP_HANDLE_PARAM_BASE,
35 NVMAP_HANDLE_PARAM_HEAP,
36};
37
38enum {
39 NVMAP_CACHE_OP_WB = 0,
40 NVMAP_CACHE_OP_INV,
41 NVMAP_CACHE_OP_WB_INV,
42};
43
44
45struct nvmap_create_handle {
46 union {
47 __u32 key; /* ClaimPreservedHandle */
48 __u32 id; /* FromId */
49 __u32 size; /* CreateHandle */
50 };
51 __u32 handle;
52};
53
54struct nvmap_alloc_handle {
55 __u32 handle;
56 __u32 heap_mask;
57 __u32 flags;
58 __u32 align;
59};
60
61struct nvmap_map_caller {
62 __u32 handle; /* hmem */
63 __u32 offset; /* offset into hmem; should be page-aligned */
64 __u32 length; /* number of bytes to map */
65 __u32 flags;
66 unsigned long addr; /* user pointer */
67};
68
69struct nvmap_rw_handle {
70 unsigned long addr; /* user pointer */
71 __u32 handle; /* hmem */
72 __u32 offset; /* offset into hmem */
73 __u32 elem_size; /* individual atom size */
74 __u32 hmem_stride; /* delta in bytes between atoms in hmem */
75 __u32 user_stride; /* delta in bytes between atoms in user */
76 __u32 count; /* number of atoms to copy */
77};
78
79struct nvmap_pin_handle {
80 unsigned long handles; /* array of handles to pin/unpin */
81 unsigned long addr; /* array of addresses to return */
82 __u32 count; /* number of entries in handles */
83};
84
85struct nvmap_handle_param {
86 __u32 handle;
87 __u32 param;
88 unsigned long result;
89};
90
91struct nvmap_cache_op {
92 unsigned long addr;
93 __u32 handle;
94 __u32 len;
95 __s32 op;
96};
97
98#define NVMAP_IOC_MAGIC 'N'
99
100/* Creates a new memory handle. On input, the argument is the size of the new
101 * handle; on return, the argument is the name of the new handle
102 */
103#define NVMAP_IOC_CREATE _IOWR(NVMAP_IOC_MAGIC, 0, struct nvmap_create_handle)
104#define NVMAP_IOC_CLAIM _IOWR(NVMAP_IOC_MAGIC, 1, struct nvmap_create_handle)
105#define NVMAP_IOC_FROM_ID _IOWR(NVMAP_IOC_MAGIC, 2, struct nvmap_create_handle)
106
107/* Actually allocates memory for the specified handle */
108#define NVMAP_IOC_ALLOC _IOW(NVMAP_IOC_MAGIC, 3, struct nvmap_alloc_handle)
109
110/* Frees a memory handle, unpinning any pinned pages and unmapping any mappings
111 */
112#define NVMAP_IOC_FREE _IO(NVMAP_IOC_MAGIC, 4)
113
114/* Maps the region of the specified handle into a user-provided virtual address
115 * that was previously created via an mmap syscall on this fd */
116#define NVMAP_IOC_MMAP _IOWR(NVMAP_IOC_MAGIC, 5, struct nvmap_map_caller)
117
118/* Reads/writes data (possibly strided) from a user-provided buffer into the
119 * hmem at the specified offset */
120#define NVMAP_IOC_WRITE _IOW(NVMAP_IOC_MAGIC, 6, struct nvmap_rw_handle)
121#define NVMAP_IOC_READ _IOW(NVMAP_IOC_MAGIC, 7, struct nvmap_rw_handle)
122
123#define NVMAP_IOC_PARAM _IOWR(NVMAP_IOC_MAGIC, 8, struct nvmap_handle_param)
124
125/* Pins a list of memory handles into IO-addressable memory (either IOVMM
126 * space or physical memory, depending on the allocation), and returns the
127 * address. Handles may be pinned recursively. */
128#define NVMAP_IOC_PIN_MULT _IOWR(NVMAP_IOC_MAGIC, 10, struct nvmap_pin_handle)
129#define NVMAP_IOC_UNPIN_MULT _IOW(NVMAP_IOC_MAGIC, 11, struct nvmap_pin_handle)
130
131#define NVMAP_IOC_CACHE _IOW(NVMAP_IOC_MAGIC, 12, struct nvmap_cache_op)
132
133/* Returns a global ID usable to allow a remote process to create a handle
134 * reference to the same handle */
135#define NVMAP_IOC_GET_ID _IOWR(NVMAP_IOC_MAGIC, 13, struct nvmap_create_handle)
136
137#define NVMAP_IOC_MAXNR (_IOC_NR(NVMAP_IOC_GET_ID))
138
139int nvmap_ioctl_pinop(struct file *filp, bool is_pin, void __user *arg);
140
141int nvmap_ioctl_get_param(struct file *filp, void __user* arg);
142
143int nvmap_ioctl_getid(struct file *filp, void __user *arg);
144
145int nvmap_ioctl_alloc(struct file *filp, void __user *arg);
146
147int nvmap_ioctl_free(struct file *filp, unsigned long arg);
148
149int nvmap_ioctl_create(struct file *filp, unsigned int cmd, void __user *arg);
150
151int nvmap_map_into_caller_ptr(struct file *filp, void __user *arg);
152
153int nvmap_ioctl_cache_maint(struct file *filp, void __user *arg);
154
155int nvmap_ioctl_rw_handle(struct file *filp, int is_read, void __user* arg);
156
157
158
159#endif
diff --git a/drivers/video/tegra/nvmap/nvmap_mru.c b/drivers/video/tegra/nvmap/nvmap_mru.c
new file mode 100644
index 00000000000..f54d44923eb
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_mru.c
@@ -0,0 +1,187 @@
1/*
2 * drivers/video/tegra/nvmap/nvmap_mru.c
3 *
4 * IOVMM virtualization support for nvmap
5 *
6 * Copyright (c) 2009-2011, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <linux/list.h>
24#include <linux/slab.h>
25
26#include <asm/pgtable.h>
27
28#include <mach/iovmm.h>
29
30#include "nvmap.h"
31#include "nvmap_mru.h"
32
33/* if IOVMM reclamation is enabled (CONFIG_NVMAP_RECLAIM_UNPINNED_VM),
34 * unpinned handles are placed onto a most-recently-used eviction list;
35 * multiple lists are maintained, segmented by size (sizes were chosen to
36 * roughly correspond with common sizes for graphics surfaces).
37 *
38 * if a handle is located on the MRU list, then the code below may
39 * steal its IOVMM area at any time to satisfy a pin operation if no
40 * free IOVMM space is available
41 */
42
43static const size_t mru_cutoff[] = {
44 262144, 393216, 786432, 1048576, 1572864
45};
46
47static inline struct list_head *mru_list(struct nvmap_share *share, size_t size)
48{
49 unsigned int i;
50
51 BUG_ON(!share->mru_lists);
52 for (i = 0; i < ARRAY_SIZE(mru_cutoff); i++)
53 if (size <= mru_cutoff[i])
54 break;
55
56 return &share->mru_lists[i];
57}
58
59size_t nvmap_mru_vm_size(struct tegra_iovmm_client *iovmm)
60{
61 size_t vm_size = tegra_iovmm_get_vm_size(iovmm);
62 return (vm_size >> 2) * 3;
63}
64
65/* nvmap_mru_vma_lock should be acquired by the caller before calling this */
66void nvmap_mru_insert_locked(struct nvmap_share *share, struct nvmap_handle *h)
67{
68 size_t len = h->pgalloc.area->iovm_length;
69 list_add(&h->pgalloc.mru_list, mru_list(share, len));
70}
71
72void nvmap_mru_remove(struct nvmap_share *s, struct nvmap_handle *h)
73{
74 nvmap_mru_lock(s);
75 if (!list_empty(&h->pgalloc.mru_list))
76 list_del(&h->pgalloc.mru_list);
77 nvmap_mru_unlock(s);
78 INIT_LIST_HEAD(&h->pgalloc.mru_list);
79}
80
81/* returns a tegra_iovmm_area for a handle. if the handle already has
82 * an iovmm_area allocated, the handle is simply removed from its MRU list
83 * and the existing iovmm_area is returned.
84 *
85 * if no existing allocation exists, try to allocate a new IOVMM area.
86 *
87 * if a new area can not be allocated, try to re-use the most-recently-unpinned
88 * handle's allocation.
89 *
90 * and if that fails, iteratively evict handles from the MRU lists and free
91 * their allocations, until the new allocation succeeds.
92 */
93struct tegra_iovmm_area *nvmap_handle_iovmm_locked(struct nvmap_client *c,
94 struct nvmap_handle *h)
95{
96 struct list_head *mru;
97 struct nvmap_handle *evict = NULL;
98 struct tegra_iovmm_area *vm = NULL;
99 unsigned int i, idx;
100 pgprot_t prot;
101
102 BUG_ON(!h || !c || !c->share);
103
104 prot = nvmap_pgprot(h, pgprot_kernel);
105
106 if (h->pgalloc.area) {
107 BUG_ON(list_empty(&h->pgalloc.mru_list));
108 list_del(&h->pgalloc.mru_list);
109 INIT_LIST_HEAD(&h->pgalloc.mru_list);
110 return h->pgalloc.area;
111 }
112
113 vm = tegra_iovmm_create_vm(c->share->iovmm, NULL,
114 h->size, h->align, prot,
115 h->pgalloc.iovm_addr);
116
117 if (vm) {
118 INIT_LIST_HEAD(&h->pgalloc.mru_list);
119 return vm;
120 }
121 /* if client is looking for specific iovm address, return from here. */
122 if ((vm == NULL) && (h->pgalloc.iovm_addr != 0))
123 return NULL;
124 /* attempt to re-use the most recently unpinned IOVMM area in the
125 * same size bin as the current handle. If that fails, iteratively
126 * evict handles (starting from the current bin) until an allocation
127 * succeeds or no more areas can be evicted */
128 mru = mru_list(c->share, h->size);
129 if (!list_empty(mru))
130 evict = list_first_entry(mru, struct nvmap_handle,
131 pgalloc.mru_list);
132
133 if (evict && evict->pgalloc.area->iovm_length >= h->size) {
134 list_del(&evict->pgalloc.mru_list);
135 vm = evict->pgalloc.area;
136 evict->pgalloc.area = NULL;
137 INIT_LIST_HEAD(&evict->pgalloc.mru_list);
138 return vm;
139 }
140
141 idx = mru - c->share->mru_lists;
142
143 for (i = 0; i < c->share->nr_mru && !vm; i++, idx++) {
144 if (idx >= c->share->nr_mru)
145 idx = 0;
146 mru = &c->share->mru_lists[idx];
147 while (!list_empty(mru) && !vm) {
148 evict = list_first_entry(mru, struct nvmap_handle,
149 pgalloc.mru_list);
150
151 BUG_ON(atomic_read(&evict->pin) != 0);
152 BUG_ON(!evict->pgalloc.area);
153 list_del(&evict->pgalloc.mru_list);
154 INIT_LIST_HEAD(&evict->pgalloc.mru_list);
155 tegra_iovmm_free_vm(evict->pgalloc.area);
156 evict->pgalloc.area = NULL;
157 vm = tegra_iovmm_create_vm(c->share->iovmm,
158 NULL, h->size, h->align,
159 prot, h->pgalloc.iovm_addr);
160 }
161 }
162 return vm;
163}
164
165int nvmap_mru_init(struct nvmap_share *share)
166{
167 int i;
168 mutex_init(&share->mru_lock);
169 share->nr_mru = ARRAY_SIZE(mru_cutoff) + 1;
170
171 share->mru_lists = kzalloc(sizeof(struct list_head) * share->nr_mru,
172 GFP_KERNEL);
173
174 if (!share->mru_lists)
175 return -ENOMEM;
176
177 for (i = 0; i < share->nr_mru; i++)
178 INIT_LIST_HEAD(&share->mru_lists[i]);
179
180 return 0;
181}
182
183void nvmap_mru_destroy(struct nvmap_share *share)
184{
185 kfree(share->mru_lists);
186 share->mru_lists = NULL;
187}
diff --git a/drivers/video/tegra/nvmap/nvmap_mru.h b/drivers/video/tegra/nvmap/nvmap_mru.h
new file mode 100644
index 00000000000..6c94630bc3e
--- /dev/null
+++ b/drivers/video/tegra/nvmap/nvmap_mru.h
@@ -0,0 +1,84 @@
1/*
2 * drivers/video/tegra/nvmap_mru.c
3 *
4 * IOVMM virtualization support for nvmap
5 *
6 * Copyright (c) 2009-2010, NVIDIA Corporation.
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 as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23
24#ifndef __VIDEO_TEGRA_NVMAP_MRU_H
25#define __VIDEO_TEGRA_NVMAP_MRU_H
26
27#include <linux/spinlock.h>
28
29#include "nvmap.h"
30
31struct tegra_iovmm_area;
32struct tegra_iovmm_client;
33
34#ifdef CONFIG_NVMAP_RECLAIM_UNPINNED_VM
35
36static inline void nvmap_mru_lock(struct nvmap_share *share)
37{
38 mutex_lock(&share->mru_lock);
39}
40
41static inline void nvmap_mru_unlock(struct nvmap_share *share)
42{
43 mutex_unlock(&share->mru_lock);
44}
45
46int nvmap_mru_init(struct nvmap_share *share);
47
48void nvmap_mru_destroy(struct nvmap_share *share);
49
50size_t nvmap_mru_vm_size(struct tegra_iovmm_client *iovmm);
51
52void nvmap_mru_insert_locked(struct nvmap_share *share, struct nvmap_handle *h);
53
54void nvmap_mru_remove(struct nvmap_share *s, struct nvmap_handle *h);
55
56struct tegra_iovmm_area *nvmap_handle_iovmm_locked(struct nvmap_client *c,
57 struct nvmap_handle *h);
58
59#else
60
61#define nvmap_mru_lock(_s) do { } while (0)
62#define nvmap_mru_unlock(_s) do { } while (0)
63#define nvmap_mru_init(_s) 0
64#define nvmap_mru_destroy(_s) do { } while (0)
65#define nvmap_mru_vm_size(_a) tegra_iovmm_get_vm_size(_a)
66
67static inline void nvmap_mru_insert_locked(struct nvmap_share *share,
68 struct nvmap_handle *h)
69{ }
70
71static inline void nvmap_mru_remove(struct nvmap_share *s,
72 struct nvmap_handle *h)
73{ }
74
75static inline struct tegra_iovmm_area *nvmap_handle_iovmm_locked(struct nvmap_client *c,
76 struct nvmap_handle *h)
77{
78 BUG_ON(!h->pgalloc.area);
79 return h->pgalloc.area;
80}
81
82#endif
83
84#endif