blob: 5554b72cf56a78d4b469ffe651df697b7034ddf0 [file] [log] [blame]
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001/*
2 * linux/drivers/video/omap2/dss/dispc.c
3 *
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6 *
7 * Some code and ideas taken from drivers/video/omap/ driver
8 * by Imre Deak.
9 *
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published by
12 * the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 * more details.
18 *
19 * You should have received a copy of the GNU General Public License along with
20 * this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#define DSS_SUBSYS_NAME "DISPC"
24
25#include <linux/kernel.h>
26#include <linux/dma-mapping.h>
27#include <linux/vmalloc.h>
Paul Gortmakera8a35932011-07-10 13:20:26 -040028#include <linux/export.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020029#include <linux/clk.h>
30#include <linux/io.h>
31#include <linux/jiffies.h>
32#include <linux/seq_file.h>
33#include <linux/delay.h>
34#include <linux/workqueue.h>
Tomi Valkeinenab83b142010-06-09 15:31:01 +030035#include <linux/hardirq.h>
Tomi Valkeinen24e62892011-05-23 11:51:18 +030036#include <linux/platform_device.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030037#include <linux/pm_runtime.h>
Tomi Valkeinen33366d02012-09-28 13:54:35 +030038#include <linux/sizes.h>
Tomi Valkeinen0006fd62014-09-05 19:15:03 +000039#include <linux/mfd/syscon.h>
40#include <linux/regmap.h>
41#include <linux/of.h>
Tomi Valkeinen736e60d2015-06-04 15:22:23 +030042#include <linux/component.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020043
Peter Ujfalusi32043da2016-05-27 14:40:49 +030044#include "omapdss.h"
Tomi Valkeinen80c39712009-11-12 11:41:42 +020045#include "dss.h"
Archit Tanejaa0acb552010-09-15 19:20:00 +053046#include "dss_features.h"
Archit Taneja9b372c22011-05-06 11:45:49 +053047#include "dispc.h"
Tomi Valkeinen80c39712009-11-12 11:41:42 +020048
49/* DISPC */
Sumit Semwal8613b002010-12-02 11:27:09 +000050#define DISPC_SZ_REGS SZ_4K
Tomi Valkeinen80c39712009-11-12 11:41:42 +020051
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +030052enum omap_burst_size {
53 BURST_SIZE_X2 = 0,
54 BURST_SIZE_X4 = 1,
55 BURST_SIZE_X8 = 2,
56};
57
Tomi Valkeinen80c39712009-11-12 11:41:42 +020058#define REG_GET(idx, start, end) \
59 FLD_GET(dispc_read_reg(idx), start, end)
60
61#define REG_FLD_MOD(idx, val, start, end) \
62 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
63
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053064struct dispc_features {
65 u8 sw_start;
66 u8 fp_start;
67 u8 bp_start;
68 u16 sw_max;
69 u16 vp_max;
70 u16 hp_max;
Archit Taneja33b89922012-11-14 13:50:15 +053071 u8 mgr_width_start;
72 u8 mgr_height_start;
73 u16 mgr_width_max;
74 u16 mgr_height_max;
Archit Tanejaca5ca692013-03-26 19:15:22 +053075 unsigned long max_lcd_pclk;
76 unsigned long max_tv_pclk;
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +030077 int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +030078 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053079 u16 width, u16 height, u16 out_width, u16 out_height,
80 enum omap_color_mode color_mode, bool *five_taps,
81 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +053082 u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
Tomi Valkeinen8702ee52012-10-19 15:36:11 +030083 unsigned long (*calc_core_clk) (unsigned long pclk,
Archit Taneja8ba85302012-09-26 17:00:37 +053084 u16 width, u16 height, u16 out_width, u16 out_height,
85 bool mem_to_mem);
Tomi Valkeinen42a69612012-08-22 16:56:57 +030086 u8 num_fifos;
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +030087
88 /* swap GFX & WB fifos */
89 bool gfx_fifo_workaround:1;
Tomi Valkeinencffa9472012-11-08 10:01:33 +020090
91 /* no DISPC_IRQ_FRAMEDONETV on this SoC */
92 bool no_framedone_tv:1;
Archit Tanejad0df9a22013-03-26 19:15:25 +053093
94 /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
95 bool mstandby_workaround:1;
Archit Taneja8bc65552013-12-17 16:40:21 +053096
97 bool set_max_preload:1;
Tomi Valkeinenf2aee312015-04-10 12:48:34 +030098
99 /* PIXEL_INC is not added to the last pixel of a line */
100 bool last_pixel_inc_missing:1;
Tomi Valkeinene5f80912015-10-21 13:08:59 +0300101
102 /* POL_FREQ has ALIGN bit */
103 bool supports_sync_align:1;
Tomi Valkeinen20efbc32015-11-04 17:10:44 +0200104
105 bool has_writeback:1;
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +0200106
107 bool supports_double_pixel:1;
Tomi Valkeinenb7536d62016-01-13 18:41:36 +0200108
109 /*
110 * Field order for VENC is different than HDMI. We should handle this in
111 * some intelligent manner, but as the SoCs have either HDMI or VENC,
112 * never both, we can just use this flag for now.
113 */
114 bool reverse_ilace_field_order:1;
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300115
116 bool has_gamma_table:1;
Jyri Sarhafbff0102016-06-07 15:09:16 +0300117
118 bool has_gamma_i734_bug:1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530119};
120
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300121#define DISPC_MAX_NR_FIFOS 5
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300122#define DISPC_MAX_CHANNEL_GAMMA 4
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300123
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200124static struct {
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +0000125 struct platform_device *pdev;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200126 void __iomem *base;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300127
archit tanejaaffe3602011-02-23 08:41:03 +0000128 int irq;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +0300129 irq_handler_t user_handler;
130 void *user_data;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200131
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +0200132 unsigned long core_clk_rate;
Tomi Valkeinen5391e872013-05-16 10:44:13 +0300133 unsigned long tv_pclk_rate;
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +0200134
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300135 u32 fifo_size[DISPC_MAX_NR_FIFOS];
136 /* maps which plane is using a fifo. fifo-id -> plane-id */
137 int fifo_assignment[DISPC_MAX_NR_FIFOS];
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200138
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300139 bool ctx_valid;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200140 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200141
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300142 u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA];
143
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530144 const struct dispc_features *feat;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +0300145
146 bool is_enabled;
Tomi Valkeinen0006fd62014-09-05 19:15:03 +0000147
148 struct regmap *syscon_pol;
149 u32 syscon_pol_offset;
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200150
151 /* DISPC_CONTROL & DISPC_CONFIG lock*/
152 spinlock_t control_lock;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200153} dispc;
154
Amber Jain0d66cbb2011-05-19 19:47:54 +0530155enum omap_color_component {
156 /* used for all color formats for OMAP3 and earlier
157 * and for RGB and Y color component on OMAP4
158 */
159 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
160 /* used for UV component for
161 * OMAP_DSS_COLOR_YUV2, OMAP_DSS_COLOR_UYVY, OMAP_DSS_COLOR_NV12
162 * color formats on OMAP4
163 */
164 DISPC_COLOR_COMPONENT_UV = 1 << 1,
165};
166
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530167enum mgr_reg_fields {
168 DISPC_MGR_FLD_ENABLE,
169 DISPC_MGR_FLD_STNTFT,
170 DISPC_MGR_FLD_GO,
171 DISPC_MGR_FLD_TFTDATALINES,
172 DISPC_MGR_FLD_STALLMODE,
173 DISPC_MGR_FLD_TCKENABLE,
174 DISPC_MGR_FLD_TCKSELECTION,
175 DISPC_MGR_FLD_CPR,
176 DISPC_MGR_FLD_FIFOHANDCHECK,
177 /* used to maintain a count of the above fields */
178 DISPC_MGR_FLD_NUM,
179};
180
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300181struct dispc_reg_field {
182 u16 reg;
183 u8 high;
184 u8 low;
185};
186
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300187struct dispc_gamma_desc {
188 u32 len;
189 u32 bits;
190 u16 reg;
191 bool has_index;
192};
193
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530194static const struct {
195 const char *name;
196 u32 vsync_irq;
197 u32 framedone_irq;
198 u32 sync_lost_irq;
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300199 struct dispc_gamma_desc gamma;
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300200 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530201} mgr_desc[] = {
202 [OMAP_DSS_CHANNEL_LCD] = {
203 .name = "LCD",
204 .vsync_irq = DISPC_IRQ_VSYNC,
205 .framedone_irq = DISPC_IRQ_FRAMEDONE,
206 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300207 .gamma = {
208 .len = 256,
209 .bits = 8,
210 .reg = DISPC_GAMMA_TABLE0,
211 .has_index = true,
212 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530213 .reg_desc = {
214 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
215 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
216 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
217 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
218 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
219 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
220 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
221 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
222 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
223 },
224 },
225 [OMAP_DSS_CHANNEL_DIGIT] = {
226 .name = "DIGIT",
227 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200228 .framedone_irq = DISPC_IRQ_FRAMEDONETV,
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530229 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300230 .gamma = {
231 .len = 1024,
232 .bits = 10,
233 .reg = DISPC_GAMMA_TABLE2,
234 .has_index = false,
235 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530236 .reg_desc = {
237 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
238 [DISPC_MGR_FLD_STNTFT] = { },
239 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
240 [DISPC_MGR_FLD_TFTDATALINES] = { },
241 [DISPC_MGR_FLD_STALLMODE] = { },
242 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
243 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
244 [DISPC_MGR_FLD_CPR] = { },
245 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
246 },
247 },
248 [OMAP_DSS_CHANNEL_LCD2] = {
249 .name = "LCD2",
250 .vsync_irq = DISPC_IRQ_VSYNC2,
251 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
252 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300253 .gamma = {
254 .len = 256,
255 .bits = 8,
256 .reg = DISPC_GAMMA_TABLE1,
257 .has_index = true,
258 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530259 .reg_desc = {
260 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
261 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
262 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
263 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
264 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
265 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
266 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
267 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
268 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
269 },
270 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530271 [OMAP_DSS_CHANNEL_LCD3] = {
272 .name = "LCD3",
273 .vsync_irq = DISPC_IRQ_VSYNC3,
274 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
275 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300276 .gamma = {
277 .len = 256,
278 .bits = 8,
279 .reg = DISPC_GAMMA_TABLE3,
280 .has_index = true,
281 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530282 .reg_desc = {
283 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
284 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
285 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
286 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
287 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
288 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
289 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
290 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
291 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
292 },
293 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530294};
295
Archit Taneja6e5264b2012-09-11 12:04:47 +0530296struct color_conv_coef {
297 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
298 int full_range;
299};
300
Tomi Valkeinen65904152015-11-04 17:10:57 +0200301static unsigned long dispc_fclk_rate(void);
302static unsigned long dispc_core_clk_rate(void);
303static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
304static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
305
Archit Taneja3e8a6ff2012-09-26 16:58:52 +0530306static unsigned long dispc_plane_pclk_rate(enum omap_plane plane);
307static unsigned long dispc_plane_lclk_rate(enum omap_plane plane);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200308
Archit Taneja55978cc2011-05-06 11:45:51 +0530309static inline void dispc_write_reg(const u16 idx, u32 val)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200310{
Archit Taneja55978cc2011-05-06 11:45:51 +0530311 __raw_writel(val, dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200312}
313
Archit Taneja55978cc2011-05-06 11:45:51 +0530314static inline u32 dispc_read_reg(const u16 idx)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200315{
Archit Taneja55978cc2011-05-06 11:45:51 +0530316 return __raw_readl(dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200317}
318
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530319static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
320{
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300321 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530322 return REG_GET(rfld.reg, rfld.high, rfld.low);
323}
324
325static void mgr_fld_write(enum omap_channel channel,
326 enum mgr_reg_fields regfld, int val) {
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300327 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200328 const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG;
329 unsigned long flags;
330
331 if (need_lock)
332 spin_lock_irqsave(&dispc.control_lock, flags);
333
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530334 REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200335
336 if (need_lock)
337 spin_unlock_irqrestore(&dispc.control_lock, flags);
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530338}
339
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200340#define SR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530341 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200342#define RR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530343 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200344
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300345static void dispc_save_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200346{
Archit Tanejac6104b82011-08-05 19:06:02 +0530347 int i, j;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200348
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300349 DSSDBG("dispc_save_context\n");
350
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200351 SR(IRQENABLE);
352 SR(CONTROL);
353 SR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200354 SR(LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +0530355 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
356 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300357 SR(GLOBAL_ALPHA);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000358 if (dss_has_feature(FEAT_MGR_LCD2)) {
359 SR(CONTROL2);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000360 SR(CONFIG2);
361 }
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530362 if (dss_has_feature(FEAT_MGR_LCD3)) {
363 SR(CONTROL3);
364 SR(CONFIG3);
365 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200366
Archit Tanejac6104b82011-08-05 19:06:02 +0530367 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
368 SR(DEFAULT_COLOR(i));
369 SR(TRANS_COLOR(i));
370 SR(SIZE_MGR(i));
371 if (i == OMAP_DSS_CHANNEL_DIGIT)
372 continue;
373 SR(TIMING_H(i));
374 SR(TIMING_V(i));
375 SR(POL_FREQ(i));
376 SR(DIVISORo(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200377
Archit Tanejac6104b82011-08-05 19:06:02 +0530378 SR(DATA_CYCLE1(i));
379 SR(DATA_CYCLE2(i));
380 SR(DATA_CYCLE3(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200381
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300382 if (dss_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530383 SR(CPR_COEF_R(i));
384 SR(CPR_COEF_G(i));
385 SR(CPR_COEF_B(i));
386 }
387 }
388
389 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
390 SR(OVL_BA0(i));
391 SR(OVL_BA1(i));
392 SR(OVL_POSITION(i));
393 SR(OVL_SIZE(i));
394 SR(OVL_ATTRIBUTES(i));
395 SR(OVL_FIFO_THRESHOLD(i));
396 SR(OVL_ROW_INC(i));
397 SR(OVL_PIXEL_INC(i));
398 if (dss_has_feature(FEAT_PRELOAD))
399 SR(OVL_PRELOAD(i));
400 if (i == OMAP_DSS_GFX) {
401 SR(OVL_WINDOW_SKIP(i));
402 SR(OVL_TABLE_BA(i));
403 continue;
404 }
405 SR(OVL_FIR(i));
406 SR(OVL_PICTURE_SIZE(i));
407 SR(OVL_ACCU0(i));
408 SR(OVL_ACCU1(i));
409
410 for (j = 0; j < 8; j++)
411 SR(OVL_FIR_COEF_H(i, j));
412
413 for (j = 0; j < 8; j++)
414 SR(OVL_FIR_COEF_HV(i, j));
415
416 for (j = 0; j < 5; j++)
417 SR(OVL_CONV_COEF(i, j));
418
419 if (dss_has_feature(FEAT_FIR_COEF_V)) {
420 for (j = 0; j < 8; j++)
421 SR(OVL_FIR_COEF_V(i, j));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300422 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000423
Archit Tanejac6104b82011-08-05 19:06:02 +0530424 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
425 SR(OVL_BA0_UV(i));
426 SR(OVL_BA1_UV(i));
427 SR(OVL_FIR2(i));
428 SR(OVL_ACCU2_0(i));
429 SR(OVL_ACCU2_1(i));
430
431 for (j = 0; j < 8; j++)
432 SR(OVL_FIR_COEF_H2(i, j));
433
434 for (j = 0; j < 8; j++)
435 SR(OVL_FIR_COEF_HV2(i, j));
436
437 for (j = 0; j < 8; j++)
438 SR(OVL_FIR_COEF_V2(i, j));
439 }
440 if (dss_has_feature(FEAT_ATTR2))
441 SR(OVL_ATTRIBUTES2(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000442 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200443
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600444 if (dss_has_feature(FEAT_CORE_CLK_DIV))
445 SR(DIVISOR);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300446
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300447 dispc.ctx_valid = true;
448
Tomi Valkeinen9229b512014-02-14 09:37:09 +0200449 DSSDBG("context saved\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200450}
451
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300452static void dispc_restore_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200453{
Tomi Valkeinen9229b512014-02-14 09:37:09 +0200454 int i, j;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300455
456 DSSDBG("dispc_restore_context\n");
457
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300458 if (!dispc.ctx_valid)
459 return;
460
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200461 /*RR(IRQENABLE);*/
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200462 /*RR(CONTROL);*/
463 RR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200464 RR(LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +0530465 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
466 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300467 RR(GLOBAL_ALPHA);
Archit Tanejac6104b82011-08-05 19:06:02 +0530468 if (dss_has_feature(FEAT_MGR_LCD2))
Sumit Semwal2a205f32010-12-02 11:27:12 +0000469 RR(CONFIG2);
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530470 if (dss_has_feature(FEAT_MGR_LCD3))
471 RR(CONFIG3);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200472
Archit Tanejac6104b82011-08-05 19:06:02 +0530473 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
474 RR(DEFAULT_COLOR(i));
475 RR(TRANS_COLOR(i));
476 RR(SIZE_MGR(i));
477 if (i == OMAP_DSS_CHANNEL_DIGIT)
478 continue;
479 RR(TIMING_H(i));
480 RR(TIMING_V(i));
481 RR(POL_FREQ(i));
482 RR(DIVISORo(i));
Archit Taneja9b372c22011-05-06 11:45:49 +0530483
Archit Tanejac6104b82011-08-05 19:06:02 +0530484 RR(DATA_CYCLE1(i));
485 RR(DATA_CYCLE2(i));
486 RR(DATA_CYCLE3(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000487
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300488 if (dss_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530489 RR(CPR_COEF_R(i));
490 RR(CPR_COEF_G(i));
491 RR(CPR_COEF_B(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300492 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000493 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200494
Archit Tanejac6104b82011-08-05 19:06:02 +0530495 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
496 RR(OVL_BA0(i));
497 RR(OVL_BA1(i));
498 RR(OVL_POSITION(i));
499 RR(OVL_SIZE(i));
500 RR(OVL_ATTRIBUTES(i));
501 RR(OVL_FIFO_THRESHOLD(i));
502 RR(OVL_ROW_INC(i));
503 RR(OVL_PIXEL_INC(i));
504 if (dss_has_feature(FEAT_PRELOAD))
505 RR(OVL_PRELOAD(i));
506 if (i == OMAP_DSS_GFX) {
507 RR(OVL_WINDOW_SKIP(i));
508 RR(OVL_TABLE_BA(i));
509 continue;
510 }
511 RR(OVL_FIR(i));
512 RR(OVL_PICTURE_SIZE(i));
513 RR(OVL_ACCU0(i));
514 RR(OVL_ACCU1(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200515
Archit Tanejac6104b82011-08-05 19:06:02 +0530516 for (j = 0; j < 8; j++)
517 RR(OVL_FIR_COEF_H(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200518
Archit Tanejac6104b82011-08-05 19:06:02 +0530519 for (j = 0; j < 8; j++)
520 RR(OVL_FIR_COEF_HV(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200521
Archit Tanejac6104b82011-08-05 19:06:02 +0530522 for (j = 0; j < 5; j++)
523 RR(OVL_CONV_COEF(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200524
Archit Tanejac6104b82011-08-05 19:06:02 +0530525 if (dss_has_feature(FEAT_FIR_COEF_V)) {
526 for (j = 0; j < 8; j++)
527 RR(OVL_FIR_COEF_V(i, j));
528 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200529
Archit Tanejac6104b82011-08-05 19:06:02 +0530530 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
531 RR(OVL_BA0_UV(i));
532 RR(OVL_BA1_UV(i));
533 RR(OVL_FIR2(i));
534 RR(OVL_ACCU2_0(i));
535 RR(OVL_ACCU2_1(i));
536
537 for (j = 0; j < 8; j++)
538 RR(OVL_FIR_COEF_H2(i, j));
539
540 for (j = 0; j < 8; j++)
541 RR(OVL_FIR_COEF_HV2(i, j));
542
543 for (j = 0; j < 8; j++)
544 RR(OVL_FIR_COEF_V2(i, j));
545 }
546 if (dss_has_feature(FEAT_ATTR2))
547 RR(OVL_ATTRIBUTES2(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300548 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200549
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600550 if (dss_has_feature(FEAT_CORE_CLK_DIV))
551 RR(DIVISOR);
552
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200553 /* enable last, because LCD & DIGIT enable are here */
554 RR(CONTROL);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000555 if (dss_has_feature(FEAT_MGR_LCD2))
556 RR(CONTROL2);
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530557 if (dss_has_feature(FEAT_MGR_LCD3))
558 RR(CONTROL3);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200559 /* clear spurious SYNC_LOST_DIGIT interrupts */
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +0300560 dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200561
562 /*
563 * enable last so IRQs won't trigger before
564 * the context is fully restored
565 */
566 RR(IRQENABLE);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300567
568 DSSDBG("context restored\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200569}
570
571#undef SR
572#undef RR
573
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300574int dispc_runtime_get(void)
575{
576 int r;
577
578 DSSDBG("dispc_runtime_get\n");
579
580 r = pm_runtime_get_sync(&dispc.pdev->dev);
581 WARN_ON(r < 0);
582 return r < 0 ? r : 0;
583}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200584EXPORT_SYMBOL(dispc_runtime_get);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300585
586void dispc_runtime_put(void)
587{
588 int r;
589
590 DSSDBG("dispc_runtime_put\n");
591
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +0200592 r = pm_runtime_put_sync(&dispc.pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300593 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300594}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200595EXPORT_SYMBOL(dispc_runtime_put);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300596
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200597u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
598{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530599 return mgr_desc[channel].vsync_irq;
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200600}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200601EXPORT_SYMBOL(dispc_mgr_get_vsync_irq);
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200602
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200603u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
604{
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200605 if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
606 return 0;
607
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530608 return mgr_desc[channel].framedone_irq;
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200609}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200610EXPORT_SYMBOL(dispc_mgr_get_framedone_irq);
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200611
Tomi Valkeinencb699202012-10-17 10:38:52 +0300612u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
613{
614 return mgr_desc[channel].sync_lost_irq;
615}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200616EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq);
Tomi Valkeinencb699202012-10-17 10:38:52 +0300617
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530618u32 dispc_wb_get_framedone_irq(void)
619{
620 return DISPC_IRQ_FRAMEDONEWB;
621}
622
Laurent Pinchart03af8152016-04-18 03:09:48 +0300623void dispc_mgr_enable(enum omap_channel channel, bool enable)
624{
625 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
626 /* flush posted write */
627 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
628}
629EXPORT_SYMBOL(dispc_mgr_enable);
630
631static bool dispc_mgr_is_enabled(enum omap_channel channel)
632{
633 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
634}
635
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300636bool dispc_mgr_go_busy(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200637{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530638 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200639}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200640EXPORT_SYMBOL(dispc_mgr_go_busy);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200641
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +0300642void dispc_mgr_go(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200643{
Luis de Bethencourt0bcfdba2015-10-15 13:29:38 +0100644 WARN_ON(!dispc_mgr_is_enabled(channel));
Tomi Valkeinen3c91ee82012-10-19 15:06:07 +0300645 WARN_ON(dispc_mgr_go_busy(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200646
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530647 DSSDBG("GO %s\n", mgr_desc[channel].name);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200648
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530649 mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200650}
Tomi Valkeinen348be692012-11-07 18:17:35 +0200651EXPORT_SYMBOL(dispc_mgr_go);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200652
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530653bool dispc_wb_go_busy(void)
654{
655 return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
656}
657
658void dispc_wb_go(void)
659{
660 enum omap_plane plane = OMAP_DSS_WB;
661 bool enable, go;
662
663 enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
664
665 if (!enable)
666 return;
667
668 go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
669 if (go) {
670 DSSERR("GO bit not down for WB\n");
671 return;
672 }
673
674 REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
675}
676
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300677static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200678{
Archit Taneja9b372c22011-05-06 11:45:49 +0530679 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200680}
681
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300682static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200683{
Archit Taneja9b372c22011-05-06 11:45:49 +0530684 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200685}
686
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300687static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200688{
Archit Taneja9b372c22011-05-06 11:45:49 +0530689 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200690}
691
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300692static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530693{
694 BUG_ON(plane == OMAP_DSS_GFX);
695
696 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
697}
698
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300699static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg,
700 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530701{
702 BUG_ON(plane == OMAP_DSS_GFX);
703
704 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
705}
706
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300707static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530708{
709 BUG_ON(plane == OMAP_DSS_GFX);
710
711 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
712}
713
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530714static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc,
715 int fir_vinc, int five_taps,
716 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200717{
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530718 const struct dispc_coef *h_coef, *v_coef;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200719 int i;
720
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530721 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
722 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200723
724 for (i = 0; i < 8; i++) {
725 u32 h, hv;
726
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530727 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
728 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
729 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
730 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
731 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
732 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
733 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
734 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200735
Amber Jain0d66cbb2011-05-19 19:47:54 +0530736 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300737 dispc_ovl_write_firh_reg(plane, i, h);
738 dispc_ovl_write_firhv_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530739 } else {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300740 dispc_ovl_write_firh2_reg(plane, i, h);
741 dispc_ovl_write_firhv2_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530742 }
743
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200744 }
745
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200746 if (five_taps) {
747 for (i = 0; i < 8; i++) {
748 u32 v;
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530749 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
750 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530751 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300752 dispc_ovl_write_firv_reg(plane, i, v);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530753 else
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300754 dispc_ovl_write_firv2_reg(plane, i, v);
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200755 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200756 }
757}
758
Archit Taneja6e5264b2012-09-11 12:04:47 +0530759
760static void dispc_ovl_write_color_conv_coef(enum omap_plane plane,
761 const struct color_conv_coef *ct)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200762{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200763#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
764
Archit Taneja6e5264b2012-09-11 12:04:47 +0530765 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
766 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
767 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
768 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
769 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200770
Archit Taneja6e5264b2012-09-11 12:04:47 +0530771 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200772
773#undef CVAL
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200774}
775
Archit Taneja6e5264b2012-09-11 12:04:47 +0530776static void dispc_setup_color_conv_coef(void)
777{
778 int i;
779 int num_ovl = dss_feat_get_num_ovls();
Archit Taneja6e5264b2012-09-11 12:04:47 +0530780 const struct color_conv_coef ctbl_bt601_5_ovl = {
Tomi Valkeinen7d18bbe2015-11-04 17:10:52 +0200781 /* YUV -> RGB */
Archit Taneja6e5264b2012-09-11 12:04:47 +0530782 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
783 };
784 const struct color_conv_coef ctbl_bt601_5_wb = {
Tomi Valkeinen7d18bbe2015-11-04 17:10:52 +0200785 /* RGB -> YUV */
786 66, 129, 25, 112, -94, -18, -38, -74, 112, 0,
Archit Taneja6e5264b2012-09-11 12:04:47 +0530787 };
788
789 for (i = 1; i < num_ovl; i++)
790 dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
791
Tomi Valkeinen20efbc32015-11-04 17:10:44 +0200792 if (dispc.feat->has_writeback)
793 dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb);
Archit Taneja6e5264b2012-09-11 12:04:47 +0530794}
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200795
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300796static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200797{
Archit Taneja9b372c22011-05-06 11:45:49 +0530798 dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200799}
800
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300801static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200802{
Archit Taneja9b372c22011-05-06 11:45:49 +0530803 dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200804}
805
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300806static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530807{
808 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
809}
810
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300811static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530812{
813 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
814}
815
Archit Tanejad79db852012-09-22 12:30:17 +0530816static void dispc_ovl_set_pos(enum omap_plane plane,
817 enum omap_overlay_caps caps, int x, int y)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200818{
Archit Tanejad79db852012-09-22 12:30:17 +0530819 u32 val;
820
821 if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
822 return;
823
824 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530825
826 dispc_write_reg(DISPC_OVL_POSITION(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200827}
828
Archit Taneja78b687f2012-09-21 14:51:49 +0530829static void dispc_ovl_set_input_size(enum omap_plane plane, int width,
830 int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200831{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200832 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530833
Archit Taneja36d87d92012-07-28 22:59:03 +0530834 if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
Archit Taneja9b372c22011-05-06 11:45:49 +0530835 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
836 else
837 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200838}
839
Archit Taneja78b687f2012-09-21 14:51:49 +0530840static void dispc_ovl_set_output_size(enum omap_plane plane, int width,
841 int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200842{
843 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200844
845 BUG_ON(plane == OMAP_DSS_GFX);
846
847 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530848
Archit Taneja36d87d92012-07-28 22:59:03 +0530849 if (plane == OMAP_DSS_WB)
850 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
851 else
852 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200853}
854
Archit Taneja5b54ed32012-09-26 16:55:27 +0530855static void dispc_ovl_set_zorder(enum omap_plane plane,
856 enum omap_overlay_caps caps, u8 zorder)
Archit Taneja54128702011-09-08 11:29:17 +0530857{
Archit Taneja5b54ed32012-09-26 16:55:27 +0530858 if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
Archit Taneja54128702011-09-08 11:29:17 +0530859 return;
860
861 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
862}
863
864static void dispc_ovl_enable_zorder_planes(void)
865{
866 int i;
867
868 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
869 return;
870
871 for (i = 0; i < dss_feat_get_num_ovls(); i++)
872 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
873}
874
Archit Taneja5b54ed32012-09-26 16:55:27 +0530875static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane,
876 enum omap_overlay_caps caps, bool enable)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100877{
Archit Taneja5b54ed32012-09-26 16:55:27 +0530878 if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100879 return;
880
Archit Taneja9b372c22011-05-06 11:45:49 +0530881 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
Rajkumar Nfd28a392010-11-04 12:28:42 +0100882}
883
Archit Taneja5b54ed32012-09-26 16:55:27 +0530884static void dispc_ovl_setup_global_alpha(enum omap_plane plane,
885 enum omap_overlay_caps caps, u8 global_alpha)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200886{
Archit Tanejab8c095b2011-09-13 18:20:33 +0530887 static const unsigned shifts[] = { 0, 8, 16, 24, };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300888 int shift;
889
Archit Taneja5b54ed32012-09-26 16:55:27 +0530890 if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100891 return;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530892
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300893 shift = shifts[plane];
894 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200895}
896
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300897static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200898{
Archit Taneja9b372c22011-05-06 11:45:49 +0530899 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200900}
901
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300902static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200903{
Archit Taneja9b372c22011-05-06 11:45:49 +0530904 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200905}
906
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300907static void dispc_ovl_set_color_mode(enum omap_plane plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200908 enum omap_color_mode color_mode)
909{
910 u32 m = 0;
Amber Jainf20e4222011-05-19 19:47:50 +0530911 if (plane != OMAP_DSS_GFX) {
912 switch (color_mode) {
913 case OMAP_DSS_COLOR_NV12:
914 m = 0x0; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530915 case OMAP_DSS_COLOR_RGBX16:
Amber Jainf20e4222011-05-19 19:47:50 +0530916 m = 0x1; break;
917 case OMAP_DSS_COLOR_RGBA16:
918 m = 0x2; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530919 case OMAP_DSS_COLOR_RGB12U:
Amber Jainf20e4222011-05-19 19:47:50 +0530920 m = 0x4; break;
921 case OMAP_DSS_COLOR_ARGB16:
922 m = 0x5; break;
923 case OMAP_DSS_COLOR_RGB16:
924 m = 0x6; break;
925 case OMAP_DSS_COLOR_ARGB16_1555:
926 m = 0x7; break;
927 case OMAP_DSS_COLOR_RGB24U:
928 m = 0x8; break;
929 case OMAP_DSS_COLOR_RGB24P:
930 m = 0x9; break;
931 case OMAP_DSS_COLOR_YUV2:
932 m = 0xa; break;
933 case OMAP_DSS_COLOR_UYVY:
934 m = 0xb; break;
935 case OMAP_DSS_COLOR_ARGB32:
936 m = 0xc; break;
937 case OMAP_DSS_COLOR_RGBA32:
938 m = 0xd; break;
939 case OMAP_DSS_COLOR_RGBX32:
940 m = 0xe; break;
941 case OMAP_DSS_COLOR_XRGB16_1555:
942 m = 0xf; break;
943 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300944 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +0530945 }
946 } else {
947 switch (color_mode) {
948 case OMAP_DSS_COLOR_CLUT1:
949 m = 0x0; break;
950 case OMAP_DSS_COLOR_CLUT2:
951 m = 0x1; break;
952 case OMAP_DSS_COLOR_CLUT4:
953 m = 0x2; break;
954 case OMAP_DSS_COLOR_CLUT8:
955 m = 0x3; break;
956 case OMAP_DSS_COLOR_RGB12U:
957 m = 0x4; break;
958 case OMAP_DSS_COLOR_ARGB16:
959 m = 0x5; break;
960 case OMAP_DSS_COLOR_RGB16:
961 m = 0x6; break;
962 case OMAP_DSS_COLOR_ARGB16_1555:
963 m = 0x7; break;
964 case OMAP_DSS_COLOR_RGB24U:
965 m = 0x8; break;
966 case OMAP_DSS_COLOR_RGB24P:
967 m = 0x9; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530968 case OMAP_DSS_COLOR_RGBX16:
Amber Jainf20e4222011-05-19 19:47:50 +0530969 m = 0xa; break;
Lajos Molnar08f32672012-02-21 19:36:30 +0530970 case OMAP_DSS_COLOR_RGBA16:
Amber Jainf20e4222011-05-19 19:47:50 +0530971 m = 0xb; break;
972 case OMAP_DSS_COLOR_ARGB32:
973 m = 0xc; break;
974 case OMAP_DSS_COLOR_RGBA32:
975 m = 0xd; break;
976 case OMAP_DSS_COLOR_RGBX32:
977 m = 0xe; break;
978 case OMAP_DSS_COLOR_XRGB16_1555:
979 m = 0xf; break;
980 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300981 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +0530982 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200983 }
984
Archit Taneja9b372c22011-05-06 11:45:49 +0530985 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200986}
987
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +0530988static void dispc_ovl_configure_burst_type(enum omap_plane plane,
989 enum omap_dss_rotation_type rotation_type)
990{
991 if (dss_has_feature(FEAT_BURST_2D) == 0)
992 return;
993
994 if (rotation_type == OMAP_DSS_ROT_TILER)
995 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
996 else
997 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
998}
999
Tomi Valkeinenf4279842011-10-28 15:26:26 +03001000void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001001{
1002 int shift;
1003 u32 val;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001004 int chan = 0, chan2 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001005
1006 switch (plane) {
1007 case OMAP_DSS_GFX:
1008 shift = 8;
1009 break;
1010 case OMAP_DSS_VIDEO1:
1011 case OMAP_DSS_VIDEO2:
Archit Tanejab8c095b2011-09-13 18:20:33 +05301012 case OMAP_DSS_VIDEO3:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001013 shift = 16;
1014 break;
1015 default:
1016 BUG();
1017 return;
1018 }
1019
Archit Taneja9b372c22011-05-06 11:45:49 +05301020 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Sumit Semwal2a205f32010-12-02 11:27:12 +00001021 if (dss_has_feature(FEAT_MGR_LCD2)) {
1022 switch (channel) {
1023 case OMAP_DSS_CHANNEL_LCD:
1024 chan = 0;
1025 chan2 = 0;
1026 break;
1027 case OMAP_DSS_CHANNEL_DIGIT:
1028 chan = 1;
1029 chan2 = 0;
1030 break;
1031 case OMAP_DSS_CHANNEL_LCD2:
1032 chan = 0;
1033 chan2 = 1;
1034 break;
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +05301035 case OMAP_DSS_CHANNEL_LCD3:
1036 if (dss_has_feature(FEAT_MGR_LCD3)) {
1037 chan = 0;
1038 chan2 = 2;
1039 } else {
1040 BUG();
1041 return;
1042 }
1043 break;
Tomi Valkeinenc2665c42015-11-04 17:10:47 +02001044 case OMAP_DSS_CHANNEL_WB:
1045 chan = 0;
1046 chan2 = 3;
1047 break;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001048 default:
1049 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001050 return;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001051 }
1052
1053 val = FLD_MOD(val, chan, shift, shift);
1054 val = FLD_MOD(val, chan2, 31, 30);
1055 } else {
1056 val = FLD_MOD(val, channel, shift, shift);
1057 }
Archit Taneja9b372c22011-05-06 11:45:49 +05301058 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001059}
Tomi Valkeinen348be692012-11-07 18:17:35 +02001060EXPORT_SYMBOL(dispc_ovl_set_channel_out);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001061
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001062static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane)
1063{
1064 int shift;
1065 u32 val;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001066
1067 switch (plane) {
1068 case OMAP_DSS_GFX:
1069 shift = 8;
1070 break;
1071 case OMAP_DSS_VIDEO1:
1072 case OMAP_DSS_VIDEO2:
1073 case OMAP_DSS_VIDEO3:
1074 shift = 16;
1075 break;
1076 default:
1077 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001078 return 0;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001079 }
1080
1081 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1082
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001083 if (FLD_GET(val, shift, shift) == 1)
1084 return OMAP_DSS_CHANNEL_DIGIT;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001085
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001086 if (!dss_has_feature(FEAT_MGR_LCD2))
1087 return OMAP_DSS_CHANNEL_LCD;
1088
1089 switch (FLD_GET(val, 31, 30)) {
1090 case 0:
1091 default:
1092 return OMAP_DSS_CHANNEL_LCD;
1093 case 1:
1094 return OMAP_DSS_CHANNEL_LCD2;
1095 case 2:
1096 return OMAP_DSS_CHANNEL_LCD3;
Tomi Valkeinenc2665c42015-11-04 17:10:47 +02001097 case 3:
1098 return OMAP_DSS_CHANNEL_WB;
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001099 }
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001100}
1101
Archit Tanejad9ac7732012-09-22 12:38:19 +05301102void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
1103{
1104 enum omap_plane plane = OMAP_DSS_WB;
1105
1106 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
1107}
1108
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001109static void dispc_ovl_set_burst_size(enum omap_plane plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001110 enum omap_burst_size burst_size)
1111{
Archit Taneja8bbe09e2012-09-10 17:31:39 +05301112 static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001113 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001114
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001115 shift = shifts[plane];
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001116 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001117}
1118
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001119static void dispc_configure_burst_sizes(void)
1120{
1121 int i;
1122 const int burst_size = BURST_SIZE_X8;
1123
1124 /* Configure burst size always to maximum size */
Tomi Valkeinen392faa02012-10-15 15:37:22 +03001125 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001126 dispc_ovl_set_burst_size(i, burst_size);
Tomi Valkeinen5b354af2015-11-04 17:10:48 +02001127 if (dispc.feat->has_writeback)
1128 dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001129}
1130
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001131static u32 dispc_ovl_get_burst_size(enum omap_plane plane)
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001132{
1133 unsigned unit = dss_feat_get_burst_size_unit();
1134 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
1135 return unit * 8;
1136}
1137
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001138static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001139{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301140 if (channel == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001141 return;
1142
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301143 mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001144}
1145
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001146static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02001147 const struct omap_dss_cpr_coefs *coefs)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001148{
1149 u32 coef_r, coef_g, coef_b;
1150
Archit Tanejadd88b7a2012-06-29 14:41:30 +05301151 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001152 return;
1153
1154 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1155 FLD_VAL(coefs->rb, 9, 0);
1156 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1157 FLD_VAL(coefs->gb, 9, 0);
1158 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1159 FLD_VAL(coefs->bb, 9, 0);
1160
1161 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1162 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1163 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1164}
1165
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001166static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001167{
1168 u32 val;
1169
1170 BUG_ON(plane == OMAP_DSS_GFX);
1171
Archit Taneja9b372c22011-05-06 11:45:49 +05301172 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001173 val = FLD_MOD(val, enable, 9, 9);
Archit Taneja9b372c22011-05-06 11:45:49 +05301174 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001175}
1176
Archit Tanejad79db852012-09-22 12:30:17 +05301177static void dispc_ovl_enable_replication(enum omap_plane plane,
1178 enum omap_overlay_caps caps, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001179{
Archit Tanejab8c095b2011-09-13 18:20:33 +05301180 static const unsigned shifts[] = { 5, 10, 10, 10 };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001181 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001182
Archit Tanejad79db852012-09-22 12:30:17 +05301183 if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
1184 return;
1185
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001186 shift = shifts[plane];
1187 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001188}
1189
Archit Taneja8f366162012-04-16 12:53:44 +05301190static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
Archit Tanejae5c09e02012-04-16 12:53:42 +05301191 u16 height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001192{
1193 u32 val;
Archit Taneja8f366162012-04-16 12:53:44 +05301194
Archit Taneja33b89922012-11-14 13:50:15 +05301195 val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) |
1196 FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0);
1197
Archit Taneja702d1442011-05-06 11:45:50 +05301198 dispc_write_reg(DISPC_SIZE_MGR(channel), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001199}
1200
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001201static void dispc_init_fifos(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001202{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001203 u32 size;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001204 int fifo;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301205 u8 start, end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001206 u32 unit;
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001207 int i;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001208
1209 unit = dss_feat_get_buffer_size_unit();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001210
Archit Tanejaa0acb552010-09-15 19:20:00 +05301211 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001212
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001213 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1214 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001215 size *= unit;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001216 dispc.fifo_size[fifo] = size;
1217
1218 /*
1219 * By default fifos are mapped directly to overlays, fifo 0 to
1220 * ovl 0, fifo 1 to ovl 1, etc.
1221 */
1222 dispc.fifo_assignment[fifo] = fifo;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001223 }
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +03001224
1225 /*
1226 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
1227 * causes problems with certain use cases, like using the tiler in 2D
1228 * mode. The below hack swaps the fifos of GFX and WB planes, thus
1229 * giving GFX plane a larger fifo. WB but should work fine with a
1230 * smaller fifo.
1231 */
1232 if (dispc.feat->gfx_fifo_workaround) {
1233 u32 v;
1234
1235 v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
1236
1237 v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
1238 v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
1239 v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
1240 v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
1241
1242 dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
1243
1244 dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
1245 dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
1246 }
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001247
1248 /*
1249 * Setup default fifo thresholds.
1250 */
1251 for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
1252 u32 low, high;
1253 const bool use_fifomerge = false;
1254 const bool manual_update = false;
1255
1256 dispc_ovl_compute_fifo_thresholds(i, &low, &high,
1257 use_fifomerge, manual_update);
1258
1259 dispc_ovl_set_fifo_threshold(i, low, high);
1260 }
Tomi Valkeinen65e116e2015-11-04 17:10:49 +02001261
1262 if (dispc.feat->has_writeback) {
1263 u32 low, high;
1264 const bool use_fifomerge = false;
1265 const bool manual_update = false;
1266
1267 dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high,
1268 use_fifomerge, manual_update);
1269
1270 dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high);
1271 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001272}
1273
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001274static u32 dispc_ovl_get_fifo_size(enum omap_plane plane)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001275{
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001276 int fifo;
1277 u32 size = 0;
1278
1279 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1280 if (dispc.fifo_assignment[fifo] == plane)
1281 size += dispc.fifo_size[fifo];
1282 }
1283
1284 return size;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001285}
1286
Tomi Valkeinen6f04e1b2011-10-31 08:58:52 +02001287void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001288{
Archit Tanejaa0acb552010-09-15 19:20:00 +05301289 u8 hi_start, hi_end, lo_start, lo_end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001290 u32 unit;
1291
1292 unit = dss_feat_get_buffer_size_unit();
1293
1294 WARN_ON(low % unit != 0);
1295 WARN_ON(high % unit != 0);
1296
1297 low /= unit;
1298 high /= unit;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301299
Archit Taneja9b372c22011-05-06 11:45:49 +05301300 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1301 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
1302
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001303 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001304 plane,
Archit Taneja9b372c22011-05-06 11:45:49 +05301305 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001306 lo_start, lo_end) * unit,
Archit Taneja9b372c22011-05-06 11:45:49 +05301307 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001308 hi_start, hi_end) * unit,
1309 low * unit, high * unit);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001310
Archit Taneja9b372c22011-05-06 11:45:49 +05301311 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
Archit Tanejaa0acb552010-09-15 19:20:00 +05301312 FLD_VAL(high, hi_start, hi_end) |
1313 FLD_VAL(low, lo_start, lo_end));
Archit Taneja8bc65552013-12-17 16:40:21 +05301314
1315 /*
1316 * configure the preload to the pipeline's high threhold, if HT it's too
1317 * large for the preload field, set the threshold to the maximum value
1318 * that can be held by the preload register
1319 */
1320 if (dss_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload &&
1321 plane != OMAP_DSS_WB)
1322 dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001323}
1324
1325void dispc_enable_fifomerge(bool enable)
1326{
Tomi Valkeinene6b0f882012-01-13 13:24:04 +02001327 if (!dss_has_feature(FEAT_FIFO_MERGE)) {
1328 WARN_ON(enable);
1329 return;
1330 }
1331
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001332 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1333 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001334}
1335
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001336void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane,
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001337 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
1338 bool manual_update)
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001339{
1340 /*
1341 * All sizes are in bytes. Both the buffer and burst are made of
1342 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1343 */
1344
1345 unsigned buf_unit = dss_feat_get_buffer_size_unit();
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001346 unsigned ovl_fifo_size, total_fifo_size, burst_size;
1347 int i;
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001348
1349 burst_size = dispc_ovl_get_burst_size(plane);
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001350 ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001351
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001352 if (use_fifomerge) {
1353 total_fifo_size = 0;
Tomi Valkeinen392faa02012-10-15 15:37:22 +03001354 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001355 total_fifo_size += dispc_ovl_get_fifo_size(i);
1356 } else {
1357 total_fifo_size = ovl_fifo_size;
1358 }
1359
1360 /*
1361 * We use the same low threshold for both fifomerge and non-fifomerge
1362 * cases, but for fifomerge we calculate the high threshold using the
1363 * combined fifo size
1364 */
1365
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001366 if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001367 *fifo_low = ovl_fifo_size - burst_size * 2;
1368 *fifo_high = total_fifo_size - burst_size;
Archit Taneja8bbe09e2012-09-10 17:31:39 +05301369 } else if (plane == OMAP_DSS_WB) {
1370 /*
1371 * Most optimal configuration for writeback is to push out data
1372 * to the interconnect the moment writeback pushes enough pixels
1373 * in the FIFO to form a burst
1374 */
1375 *fifo_low = 0;
1376 *fifo_high = burst_size;
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001377 } else {
1378 *fifo_low = ovl_fifo_size - burst_size;
1379 *fifo_high = total_fifo_size - buf_unit;
1380 }
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001381}
1382
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001383static void dispc_ovl_set_mflag(enum omap_plane plane, bool enable)
1384{
1385 int bit;
1386
1387 if (plane == OMAP_DSS_GFX)
1388 bit = 14;
1389 else
1390 bit = 23;
1391
1392 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
1393}
1394
1395static void dispc_ovl_set_mflag_threshold(enum omap_plane plane,
1396 int low, int high)
1397{
1398 dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane),
1399 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
1400}
1401
1402static void dispc_init_mflag(void)
1403{
1404 int i;
1405
Tomi Valkeinenfe59e5c2014-11-19 12:50:16 +02001406 /*
1407 * HACK: NV12 color format and MFLAG seem to have problems working
1408 * together: using two displays, and having an NV12 overlay on one of
1409 * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
1410 * Changing MFLAG thresholds and PRELOAD to certain values seem to
1411 * remove the errors, but there doesn't seem to be a clear logic on
1412 * which values work and which not.
1413 *
1414 * As a work-around, set force MFLAG to always on.
1415 */
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001416 dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE,
Tomi Valkeinenfe59e5c2014-11-19 12:50:16 +02001417 (1 << 0) | /* MFLAG_CTRL = force always on */
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001418 (0 << 2)); /* MFLAG_START = disable */
1419
1420 for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
1421 u32 size = dispc_ovl_get_fifo_size(i);
1422 u32 unit = dss_feat_get_buffer_size_unit();
1423 u32 low, high;
1424
1425 dispc_ovl_set_mflag(i, true);
1426
1427 /*
1428 * Simulation team suggests below thesholds:
1429 * HT = fifosize * 5 / 8;
1430 * LT = fifosize * 4 / 8;
1431 */
1432
1433 low = size * 4 / 8 / unit;
1434 high = size * 5 / 8 / unit;
1435
1436 dispc_ovl_set_mflag_threshold(i, low, high);
1437 }
Tomi Valkeinenecb0b362015-11-04 17:10:50 +02001438
1439 if (dispc.feat->has_writeback) {
1440 u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB);
1441 u32 unit = dss_feat_get_buffer_size_unit();
1442 u32 low, high;
1443
1444 dispc_ovl_set_mflag(OMAP_DSS_WB, true);
1445
1446 /*
1447 * Simulation team suggests below thesholds:
1448 * HT = fifosize * 5 / 8;
1449 * LT = fifosize * 4 / 8;
1450 */
1451
1452 low = size * 4 / 8 / unit;
1453 high = size * 5 / 8 / unit;
1454
1455 dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high);
1456 }
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001457}
1458
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001459static void dispc_ovl_set_fir(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301460 int hinc, int vinc,
1461 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001462{
1463 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001464
Amber Jain0d66cbb2011-05-19 19:47:54 +05301465 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1466 u8 hinc_start, hinc_end, vinc_start, vinc_end;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301467
Amber Jain0d66cbb2011-05-19 19:47:54 +05301468 dss_feat_get_reg_field(FEAT_REG_FIRHINC,
1469 &hinc_start, &hinc_end);
1470 dss_feat_get_reg_field(FEAT_REG_FIRVINC,
1471 &vinc_start, &vinc_end);
1472 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1473 FLD_VAL(hinc, hinc_start, hinc_end);
Archit Tanejaa0acb552010-09-15 19:20:00 +05301474
Amber Jain0d66cbb2011-05-19 19:47:54 +05301475 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1476 } else {
1477 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1478 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1479 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001480}
1481
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001482static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001483{
1484 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301485 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001486
Archit Taneja87a74842011-03-02 11:19:50 +05301487 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1488 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1489
1490 val = FLD_VAL(vaccu, vert_start, vert_end) |
1491 FLD_VAL(haccu, hor_start, hor_end);
1492
Archit Taneja9b372c22011-05-06 11:45:49 +05301493 dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001494}
1495
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001496static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001497{
1498 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301499 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001500
Archit Taneja87a74842011-03-02 11:19:50 +05301501 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1502 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1503
1504 val = FLD_VAL(vaccu, vert_start, vert_end) |
1505 FLD_VAL(haccu, hor_start, hor_end);
1506
Archit Taneja9b372c22011-05-06 11:45:49 +05301507 dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001508}
1509
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001510static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu,
1511 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301512{
1513 u32 val;
1514
1515 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1516 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1517}
1518
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001519static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu,
1520 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301521{
1522 u32 val;
1523
1524 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1525 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1526}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001527
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001528static void dispc_ovl_set_scale_param(enum omap_plane plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001529 u16 orig_width, u16 orig_height,
1530 u16 out_width, u16 out_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301531 bool five_taps, u8 rotation,
1532 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001533{
Amber Jain0d66cbb2011-05-19 19:47:54 +05301534 int fir_hinc, fir_vinc;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001535
Amber Jained14a3c2011-05-19 19:47:51 +05301536 fir_hinc = 1024 * orig_width / out_width;
1537 fir_vinc = 1024 * orig_height / out_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001538
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +05301539 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1540 color_comp);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001541 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301542}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001543
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301544static void dispc_ovl_set_accu_uv(enum omap_plane plane,
1545 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
1546 bool ilace, enum omap_color_mode color_mode, u8 rotation)
1547{
1548 int h_accu2_0, h_accu2_1;
1549 int v_accu2_0, v_accu2_1;
1550 int chroma_hinc, chroma_vinc;
1551 int idx;
1552
1553 struct accu {
1554 s8 h0_m, h0_n;
1555 s8 h1_m, h1_n;
1556 s8 v0_m, v0_n;
1557 s8 v1_m, v1_n;
1558 };
1559
1560 const struct accu *accu_table;
1561 const struct accu *accu_val;
1562
1563 static const struct accu accu_nv12[4] = {
1564 { 0, 1, 0, 1 , -1, 2, 0, 1 },
1565 { 1, 2, -3, 4 , 0, 1, 0, 1 },
1566 { -1, 1, 0, 1 , -1, 2, 0, 1 },
1567 { -1, 2, -1, 2 , -1, 1, 0, 1 },
1568 };
1569
1570 static const struct accu accu_nv12_ilace[4] = {
1571 { 0, 1, 0, 1 , -3, 4, -1, 4 },
1572 { -1, 4, -3, 4 , 0, 1, 0, 1 },
1573 { -1, 1, 0, 1 , -1, 4, -3, 4 },
1574 { -3, 4, -3, 4 , -1, 1, 0, 1 },
1575 };
1576
1577 static const struct accu accu_yuv[4] = {
1578 { 0, 1, 0, 1, 0, 1, 0, 1 },
1579 { 0, 1, 0, 1, 0, 1, 0, 1 },
1580 { -1, 1, 0, 1, 0, 1, 0, 1 },
1581 { 0, 1, 0, 1, -1, 1, 0, 1 },
1582 };
1583
1584 switch (rotation) {
1585 case OMAP_DSS_ROT_0:
1586 idx = 0;
1587 break;
1588 case OMAP_DSS_ROT_90:
1589 idx = 1;
1590 break;
1591 case OMAP_DSS_ROT_180:
1592 idx = 2;
1593 break;
1594 case OMAP_DSS_ROT_270:
1595 idx = 3;
1596 break;
1597 default:
1598 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001599 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301600 }
1601
1602 switch (color_mode) {
1603 case OMAP_DSS_COLOR_NV12:
1604 if (ilace)
1605 accu_table = accu_nv12_ilace;
1606 else
1607 accu_table = accu_nv12;
1608 break;
1609 case OMAP_DSS_COLOR_YUV2:
1610 case OMAP_DSS_COLOR_UYVY:
1611 accu_table = accu_yuv;
1612 break;
1613 default:
1614 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001615 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301616 }
1617
1618 accu_val = &accu_table[idx];
1619
1620 chroma_hinc = 1024 * orig_width / out_width;
1621 chroma_vinc = 1024 * orig_height / out_height;
1622
1623 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1624 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1625 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1626 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1627
1628 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1629 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1630}
1631
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001632static void dispc_ovl_set_scaling_common(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301633 u16 orig_width, u16 orig_height,
1634 u16 out_width, u16 out_height,
1635 bool ilace, bool five_taps,
1636 bool fieldmode, enum omap_color_mode color_mode,
1637 u8 rotation)
1638{
1639 int accu0 = 0;
1640 int accu1 = 0;
1641 u32 l;
1642
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001643 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301644 out_width, out_height, five_taps,
1645 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
Archit Taneja9b372c22011-05-06 11:45:49 +05301646 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001647
Archit Taneja87a74842011-03-02 11:19:50 +05301648 /* RESIZEENABLE and VERTICALTAPS */
1649 l &= ~((0x3 << 5) | (0x1 << 21));
Amber Jained14a3c2011-05-19 19:47:51 +05301650 l |= (orig_width != out_width) ? (1 << 5) : 0;
1651 l |= (orig_height != out_height) ? (1 << 6) : 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001652 l |= five_taps ? (1 << 21) : 0;
Archit Taneja87a74842011-03-02 11:19:50 +05301653
1654 /* VRESIZECONF and HRESIZECONF */
1655 if (dss_has_feature(FEAT_RESIZECONF)) {
1656 l &= ~(0x3 << 7);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301657 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1658 l |= (orig_height <= out_height) ? 0 : (1 << 8);
Archit Taneja87a74842011-03-02 11:19:50 +05301659 }
1660
1661 /* LINEBUFFERSPLIT */
1662 if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
1663 l &= ~(0x1 << 22);
1664 l |= five_taps ? (1 << 22) : 0;
1665 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001666
Archit Taneja9b372c22011-05-06 11:45:49 +05301667 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001668
1669 /*
1670 * field 0 = even field = bottom field
1671 * field 1 = odd field = top field
1672 */
1673 if (ilace && !fieldmode) {
1674 accu1 = 0;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301675 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001676 if (accu0 >= 1024/2) {
1677 accu1 = 1024/2;
1678 accu0 -= accu1;
1679 }
1680 }
1681
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001682 dispc_ovl_set_vid_accu0(plane, 0, accu0);
1683 dispc_ovl_set_vid_accu1(plane, 0, accu1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001684}
1685
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001686static void dispc_ovl_set_scaling_uv(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301687 u16 orig_width, u16 orig_height,
1688 u16 out_width, u16 out_height,
1689 bool ilace, bool five_taps,
1690 bool fieldmode, enum omap_color_mode color_mode,
1691 u8 rotation)
1692{
1693 int scale_x = out_width != orig_width;
1694 int scale_y = out_height != orig_height;
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05001695 bool chroma_upscale = plane != OMAP_DSS_WB;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301696
1697 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
1698 return;
1699 if ((color_mode != OMAP_DSS_COLOR_YUV2 &&
1700 color_mode != OMAP_DSS_COLOR_UYVY &&
1701 color_mode != OMAP_DSS_COLOR_NV12)) {
1702 /* reset chroma resampling for RGB formats */
Archit Taneja2a5561b2012-07-16 16:37:45 +05301703 if (plane != OMAP_DSS_WB)
1704 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301705 return;
1706 }
Tomi Valkeinen36377352012-05-15 15:54:15 +03001707
1708 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
1709 out_height, ilace, color_mode, rotation);
1710
Amber Jain0d66cbb2011-05-19 19:47:54 +05301711 switch (color_mode) {
1712 case OMAP_DSS_COLOR_NV12:
Archit Taneja20fbb502012-08-22 17:04:48 +05301713 if (chroma_upscale) {
1714 /* UV is subsampled by 2 horizontally and vertically */
1715 orig_height >>= 1;
1716 orig_width >>= 1;
1717 } else {
1718 /* UV is downsampled by 2 horizontally and vertically */
1719 orig_height <<= 1;
1720 orig_width <<= 1;
1721 }
1722
Amber Jain0d66cbb2011-05-19 19:47:54 +05301723 break;
1724 case OMAP_DSS_COLOR_YUV2:
1725 case OMAP_DSS_COLOR_UYVY:
Archit Taneja20fbb502012-08-22 17:04:48 +05301726 /* For YUV422 with 90/270 rotation, we don't upsample chroma */
Amber Jain0d66cbb2011-05-19 19:47:54 +05301727 if (rotation == OMAP_DSS_ROT_0 ||
Archit Taneja20fbb502012-08-22 17:04:48 +05301728 rotation == OMAP_DSS_ROT_180) {
1729 if (chroma_upscale)
1730 /* UV is subsampled by 2 horizontally */
1731 orig_width >>= 1;
1732 else
1733 /* UV is downsampled by 2 horizontally */
1734 orig_width <<= 1;
1735 }
1736
Amber Jain0d66cbb2011-05-19 19:47:54 +05301737 /* must use FIR for YUV422 if rotated */
1738 if (rotation != OMAP_DSS_ROT_0)
1739 scale_x = scale_y = true;
Archit Taneja20fbb502012-08-22 17:04:48 +05301740
Amber Jain0d66cbb2011-05-19 19:47:54 +05301741 break;
1742 default:
1743 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001744 return;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301745 }
1746
1747 if (out_width != orig_width)
1748 scale_x = true;
1749 if (out_height != orig_height)
1750 scale_y = true;
1751
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001752 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301753 out_width, out_height, five_taps,
1754 rotation, DISPC_COLOR_COMPONENT_UV);
1755
Archit Taneja2a5561b2012-07-16 16:37:45 +05301756 if (plane != OMAP_DSS_WB)
1757 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1758 (scale_x || scale_y) ? 1 : 0, 8, 8);
1759
Amber Jain0d66cbb2011-05-19 19:47:54 +05301760 /* set H scaling */
1761 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1762 /* set V scaling */
1763 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301764}
1765
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001766static void dispc_ovl_set_scaling(enum omap_plane plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301767 u16 orig_width, u16 orig_height,
1768 u16 out_width, u16 out_height,
1769 bool ilace, bool five_taps,
1770 bool fieldmode, enum omap_color_mode color_mode,
1771 u8 rotation)
1772{
1773 BUG_ON(plane == OMAP_DSS_GFX);
1774
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001775 dispc_ovl_set_scaling_common(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301776 orig_width, orig_height,
1777 out_width, out_height,
1778 ilace, five_taps,
1779 fieldmode, color_mode,
1780 rotation);
1781
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001782 dispc_ovl_set_scaling_uv(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301783 orig_width, orig_height,
1784 out_width, out_height,
1785 ilace, five_taps,
1786 fieldmode, color_mode,
1787 rotation);
1788}
1789
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001790static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation,
Archit Tanejac35eeb22013-03-26 19:15:24 +05301791 enum omap_dss_rotation_type rotation_type,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001792 bool mirroring, enum omap_color_mode color_mode)
1793{
Archit Taneja87a74842011-03-02 11:19:50 +05301794 bool row_repeat = false;
1795 int vidrot = 0;
1796
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001797 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1798 color_mode == OMAP_DSS_COLOR_UYVY) {
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001799
1800 if (mirroring) {
1801 switch (rotation) {
1802 case OMAP_DSS_ROT_0:
1803 vidrot = 2;
1804 break;
1805 case OMAP_DSS_ROT_90:
1806 vidrot = 1;
1807 break;
1808 case OMAP_DSS_ROT_180:
1809 vidrot = 0;
1810 break;
1811 case OMAP_DSS_ROT_270:
1812 vidrot = 3;
1813 break;
1814 }
1815 } else {
1816 switch (rotation) {
1817 case OMAP_DSS_ROT_0:
1818 vidrot = 0;
1819 break;
1820 case OMAP_DSS_ROT_90:
1821 vidrot = 1;
1822 break;
1823 case OMAP_DSS_ROT_180:
1824 vidrot = 2;
1825 break;
1826 case OMAP_DSS_ROT_270:
1827 vidrot = 3;
1828 break;
1829 }
1830 }
1831
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001832 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
Archit Taneja87a74842011-03-02 11:19:50 +05301833 row_repeat = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001834 else
Archit Taneja87a74842011-03-02 11:19:50 +05301835 row_repeat = false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001836 }
Archit Taneja87a74842011-03-02 11:19:50 +05301837
Tomi Valkeinen3397cc62015-04-09 13:51:30 +03001838 /*
1839 * OMAP4/5 Errata i631:
1840 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
1841 * rows beyond the framebuffer, which may cause OCP error.
1842 */
1843 if (color_mode == OMAP_DSS_COLOR_NV12 &&
1844 rotation_type != OMAP_DSS_ROT_TILER)
1845 vidrot = 1;
1846
Archit Taneja9b372c22011-05-06 11:45:49 +05301847 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
Archit Taneja87a74842011-03-02 11:19:50 +05301848 if (dss_has_feature(FEAT_ROWREPEATENABLE))
Archit Taneja9b372c22011-05-06 11:45:49 +05301849 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1850 row_repeat ? 1 : 0, 18, 18);
Archit Tanejac35eeb22013-03-26 19:15:24 +05301851
1852 if (color_mode == OMAP_DSS_COLOR_NV12) {
1853 bool doublestride = (rotation_type == OMAP_DSS_ROT_TILER) &&
1854 (rotation == OMAP_DSS_ROT_0 ||
1855 rotation == OMAP_DSS_ROT_180);
1856 /* DOUBLESTRIDE */
1857 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
1858 }
1859
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001860}
1861
1862static int color_mode_to_bpp(enum omap_color_mode color_mode)
1863{
1864 switch (color_mode) {
1865 case OMAP_DSS_COLOR_CLUT1:
1866 return 1;
1867 case OMAP_DSS_COLOR_CLUT2:
1868 return 2;
1869 case OMAP_DSS_COLOR_CLUT4:
1870 return 4;
1871 case OMAP_DSS_COLOR_CLUT8:
Amber Jainf20e4222011-05-19 19:47:50 +05301872 case OMAP_DSS_COLOR_NV12:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001873 return 8;
1874 case OMAP_DSS_COLOR_RGB12U:
1875 case OMAP_DSS_COLOR_RGB16:
1876 case OMAP_DSS_COLOR_ARGB16:
1877 case OMAP_DSS_COLOR_YUV2:
1878 case OMAP_DSS_COLOR_UYVY:
Amber Jainf20e4222011-05-19 19:47:50 +05301879 case OMAP_DSS_COLOR_RGBA16:
1880 case OMAP_DSS_COLOR_RGBX16:
1881 case OMAP_DSS_COLOR_ARGB16_1555:
1882 case OMAP_DSS_COLOR_XRGB16_1555:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001883 return 16;
1884 case OMAP_DSS_COLOR_RGB24P:
1885 return 24;
1886 case OMAP_DSS_COLOR_RGB24U:
1887 case OMAP_DSS_COLOR_ARGB32:
1888 case OMAP_DSS_COLOR_RGBA32:
1889 case OMAP_DSS_COLOR_RGBX32:
1890 return 32;
1891 default:
1892 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001893 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001894 }
1895}
1896
1897static s32 pixinc(int pixels, u8 ps)
1898{
1899 if (pixels == 1)
1900 return 1;
1901 else if (pixels > 1)
1902 return 1 + (pixels - 1) * ps;
1903 else if (pixels < 0)
1904 return 1 - (-pixels + 1) * ps;
1905 else
1906 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001907 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001908}
1909
1910static void calc_vrfb_rotation_offset(u8 rotation, bool mirror,
1911 u16 screen_width,
1912 u16 width, u16 height,
1913 enum omap_color_mode color_mode, bool fieldmode,
1914 unsigned int field_offset,
1915 unsigned *offset0, unsigned *offset1,
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05301916 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001917{
1918 u8 ps;
1919
1920 /* FIXME CLUT formats */
1921 switch (color_mode) {
1922 case OMAP_DSS_COLOR_CLUT1:
1923 case OMAP_DSS_COLOR_CLUT2:
1924 case OMAP_DSS_COLOR_CLUT4:
1925 case OMAP_DSS_COLOR_CLUT8:
1926 BUG();
1927 return;
1928 case OMAP_DSS_COLOR_YUV2:
1929 case OMAP_DSS_COLOR_UYVY:
1930 ps = 4;
1931 break;
1932 default:
1933 ps = color_mode_to_bpp(color_mode) / 8;
1934 break;
1935 }
1936
1937 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
1938 width, height);
1939
1940 /*
1941 * field 0 = even field = bottom field
1942 * field 1 = odd field = top field
1943 */
1944 switch (rotation + mirror * 4) {
1945 case OMAP_DSS_ROT_0:
1946 case OMAP_DSS_ROT_180:
1947 /*
1948 * If the pixel format is YUV or UYVY divide the width
1949 * of the image by 2 for 0 and 180 degree rotation.
1950 */
1951 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1952 color_mode == OMAP_DSS_COLOR_UYVY)
1953 width = width >> 1;
1954 case OMAP_DSS_ROT_90:
1955 case OMAP_DSS_ROT_270:
1956 *offset1 = 0;
1957 if (field_offset)
1958 *offset0 = field_offset * screen_width * ps;
1959 else
1960 *offset0 = 0;
1961
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05301962 *row_inc = pixinc(1 +
1963 (y_predecim * screen_width - x_predecim * width) +
1964 (fieldmode ? screen_width : 0), ps);
1965 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001966 break;
1967
1968 case OMAP_DSS_ROT_0 + 4:
1969 case OMAP_DSS_ROT_180 + 4:
1970 /* If the pixel format is YUV or UYVY divide the width
1971 * of the image by 2 for 0 degree and 180 degree
1972 */
1973 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
1974 color_mode == OMAP_DSS_COLOR_UYVY)
1975 width = width >> 1;
1976 case OMAP_DSS_ROT_90 + 4:
1977 case OMAP_DSS_ROT_270 + 4:
1978 *offset1 = 0;
1979 if (field_offset)
1980 *offset0 = field_offset * screen_width * ps;
1981 else
1982 *offset0 = 0;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05301983 *row_inc = pixinc(1 -
1984 (y_predecim * screen_width + x_predecim * width) -
1985 (fieldmode ? screen_width : 0), ps);
1986 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001987 break;
1988
1989 default:
1990 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001991 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001992 }
1993}
1994
1995static void calc_dma_rotation_offset(u8 rotation, bool mirror,
1996 u16 screen_width,
1997 u16 width, u16 height,
1998 enum omap_color_mode color_mode, bool fieldmode,
1999 unsigned int field_offset,
2000 unsigned *offset0, unsigned *offset1,
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302001 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002002{
2003 u8 ps;
2004 u16 fbw, fbh;
2005
2006 /* FIXME CLUT formats */
2007 switch (color_mode) {
2008 case OMAP_DSS_COLOR_CLUT1:
2009 case OMAP_DSS_COLOR_CLUT2:
2010 case OMAP_DSS_COLOR_CLUT4:
2011 case OMAP_DSS_COLOR_CLUT8:
2012 BUG();
2013 return;
2014 default:
2015 ps = color_mode_to_bpp(color_mode) / 8;
2016 break;
2017 }
2018
2019 DSSDBG("calc_rot(%d): scrw %d, %dx%d\n", rotation, screen_width,
2020 width, height);
2021
2022 /* width & height are overlay sizes, convert to fb sizes */
2023
2024 if (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180) {
2025 fbw = width;
2026 fbh = height;
2027 } else {
2028 fbw = height;
2029 fbh = width;
2030 }
2031
2032 /*
2033 * field 0 = even field = bottom field
2034 * field 1 = odd field = top field
2035 */
2036 switch (rotation + mirror * 4) {
2037 case OMAP_DSS_ROT_0:
2038 *offset1 = 0;
2039 if (field_offset)
2040 *offset0 = *offset1 + field_offset * screen_width * ps;
2041 else
2042 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302043 *row_inc = pixinc(1 +
2044 (y_predecim * screen_width - fbw * x_predecim) +
2045 (fieldmode ? screen_width : 0), ps);
2046 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2047 color_mode == OMAP_DSS_COLOR_UYVY)
2048 *pix_inc = pixinc(x_predecim, 2 * ps);
2049 else
2050 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002051 break;
2052 case OMAP_DSS_ROT_90:
2053 *offset1 = screen_width * (fbh - 1) * ps;
2054 if (field_offset)
2055 *offset0 = *offset1 + field_offset * ps;
2056 else
2057 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302058 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) +
2059 y_predecim + (fieldmode ? 1 : 0), ps);
2060 *pix_inc = pixinc(-x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002061 break;
2062 case OMAP_DSS_ROT_180:
2063 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
2064 if (field_offset)
2065 *offset0 = *offset1 - field_offset * screen_width * ps;
2066 else
2067 *offset0 = *offset1;
2068 *row_inc = pixinc(-1 -
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302069 (y_predecim * screen_width - fbw * x_predecim) -
2070 (fieldmode ? screen_width : 0), ps);
2071 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2072 color_mode == OMAP_DSS_COLOR_UYVY)
2073 *pix_inc = pixinc(-x_predecim, 2 * ps);
2074 else
2075 *pix_inc = pixinc(-x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002076 break;
2077 case OMAP_DSS_ROT_270:
2078 *offset1 = (fbw - 1) * ps;
2079 if (field_offset)
2080 *offset0 = *offset1 - field_offset * ps;
2081 else
2082 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302083 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) -
2084 y_predecim - (fieldmode ? 1 : 0), ps);
2085 *pix_inc = pixinc(x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002086 break;
2087
2088 /* mirroring */
2089 case OMAP_DSS_ROT_0 + 4:
2090 *offset1 = (fbw - 1) * ps;
2091 if (field_offset)
2092 *offset0 = *offset1 + field_offset * screen_width * ps;
2093 else
2094 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302095 *row_inc = pixinc(y_predecim * screen_width * 2 - 1 +
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002096 (fieldmode ? screen_width : 0),
2097 ps);
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302098 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2099 color_mode == OMAP_DSS_COLOR_UYVY)
2100 *pix_inc = pixinc(-x_predecim, 2 * ps);
2101 else
2102 *pix_inc = pixinc(-x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002103 break;
2104
2105 case OMAP_DSS_ROT_90 + 4:
2106 *offset1 = 0;
2107 if (field_offset)
2108 *offset0 = *offset1 + field_offset * ps;
2109 else
2110 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302111 *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) +
2112 y_predecim + (fieldmode ? 1 : 0),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002113 ps);
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302114 *pix_inc = pixinc(x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002115 break;
2116
2117 case OMAP_DSS_ROT_180 + 4:
2118 *offset1 = screen_width * (fbh - 1) * ps;
2119 if (field_offset)
2120 *offset0 = *offset1 - field_offset * screen_width * ps;
2121 else
2122 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302123 *row_inc = pixinc(1 - y_predecim * screen_width * 2 -
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002124 (fieldmode ? screen_width : 0),
2125 ps);
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302126 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2127 color_mode == OMAP_DSS_COLOR_UYVY)
2128 *pix_inc = pixinc(x_predecim, 2 * ps);
2129 else
2130 *pix_inc = pixinc(x_predecim, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002131 break;
2132
2133 case OMAP_DSS_ROT_270 + 4:
2134 *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps;
2135 if (field_offset)
2136 *offset0 = *offset1 - field_offset * ps;
2137 else
2138 *offset0 = *offset1;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302139 *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) -
2140 y_predecim - (fieldmode ? 1 : 0),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002141 ps);
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302142 *pix_inc = pixinc(-x_predecim * screen_width, ps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002143 break;
2144
2145 default:
2146 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002147 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002148 }
2149}
2150
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302151static void calc_tiler_rotation_offset(u16 screen_width, u16 width,
2152 enum omap_color_mode color_mode, bool fieldmode,
2153 unsigned int field_offset, unsigned *offset0, unsigned *offset1,
2154 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
2155{
2156 u8 ps;
2157
2158 switch (color_mode) {
2159 case OMAP_DSS_COLOR_CLUT1:
2160 case OMAP_DSS_COLOR_CLUT2:
2161 case OMAP_DSS_COLOR_CLUT4:
2162 case OMAP_DSS_COLOR_CLUT8:
2163 BUG();
2164 return;
2165 default:
2166 ps = color_mode_to_bpp(color_mode) / 8;
2167 break;
2168 }
2169
2170 DSSDBG("scrw %d, width %d\n", screen_width, width);
2171
2172 /*
2173 * field 0 = even field = bottom field
2174 * field 1 = odd field = top field
2175 */
2176 *offset1 = 0;
2177 if (field_offset)
2178 *offset0 = *offset1 + field_offset * screen_width * ps;
2179 else
2180 *offset0 = *offset1;
2181 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
2182 (fieldmode ? screen_width : 0), ps);
2183 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2184 color_mode == OMAP_DSS_COLOR_UYVY)
2185 *pix_inc = pixinc(x_predecim, 2 * ps);
2186 else
2187 *pix_inc = pixinc(x_predecim, ps);
2188}
2189
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302190/*
2191 * This function is used to avoid synclosts in OMAP3, because of some
2192 * undocumented horizontal position and timing related limitations.
2193 */
Tomi Valkeinen465ec132012-10-19 15:40:24 +03002194static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002195 const struct videomode *vm, u16 pos_x,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002196 u16 width, u16 height, u16 out_width, u16 out_height,
2197 bool five_taps)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302198{
Tomi Valkeinen230edc02012-11-05 14:40:19 +02002199 const int ds = DIV_ROUND_UP(height, out_height);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302200 unsigned long nonactive;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302201 static const u8 limits[3] = { 8, 10, 20 };
2202 u64 val, blank;
2203 int i;
2204
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002205 nonactive = vm->hactive + vm->hfront_porch + vm->hsync_len +
2206 vm->hback_porch - out_width;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302207
2208 i = 0;
2209 if (out_height < height)
2210 i++;
2211 if (out_width < width)
2212 i++;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002213 blank = div_u64((u64)(vm->hback_porch + vm->hsync_len + vm->hfront_porch) *
Peter Ujfalusi0a30e152016-09-22 14:06:49 +03002214 lclk, pclk);
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302215 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
2216 if (blank <= limits[i])
2217 return -EINVAL;
2218
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002219 /* FIXME add checks for 3-tap filter once the limitations are known */
2220 if (!five_taps)
2221 return 0;
2222
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302223 /*
2224 * Pixel data should be prepared before visible display point starts.
2225 * So, atleast DS-2 lines must have already been fetched by DISPC
2226 * during nonactive - pos_x period.
2227 */
2228 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
2229 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
Tomi Valkeinen230edc02012-11-05 14:40:19 +02002230 val, max(0, ds - 2) * width);
2231 if (val < max(0, ds - 2) * width)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302232 return -EINVAL;
2233
2234 /*
2235 * All lines need to be refilled during the nonactive period of which
2236 * only one line can be loaded during the active period. So, atleast
2237 * DS - 1 lines should be loaded during nonactive period.
2238 */
2239 val = div_u64((u64)nonactive * lclk, pclk);
2240 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
Tomi Valkeinen230edc02012-11-05 14:40:19 +02002241 val, max(0, ds - 1) * width);
2242 if (val < max(0, ds - 1) * width)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302243 return -EINVAL;
2244
2245 return 0;
2246}
2247
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002248static unsigned long calc_core_clk_five_taps(unsigned long pclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002249 const struct videomode *vm, u16 width,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302250 u16 height, u16 out_width, u16 out_height,
Sumit Semwalff1b2cde2010-12-02 11:27:11 +00002251 enum omap_color_mode color_mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002252{
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302253 u32 core_clk = 0;
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302254 u64 tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002255
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302256 if (height <= out_height && width <= out_width)
2257 return (unsigned long) pclk;
2258
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002259 if (height > out_height) {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002260 unsigned int ppl = vm->hactive;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002261
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002262 tmp = (u64)pclk * height * out_width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002263 do_div(tmp, 2 * out_height * ppl);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302264 core_clk = tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002265
Ville Syrjälä2d9c5592010-01-08 11:56:41 +02002266 if (height > 2 * out_height) {
2267 if (ppl == out_width)
2268 return 0;
2269
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002270 tmp = (u64)pclk * (height - 2 * out_height) * out_width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002271 do_div(tmp, 2 * out_height * (ppl - out_width));
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302272 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002273 }
2274 }
2275
2276 if (width > out_width) {
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002277 tmp = (u64)pclk * width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002278 do_div(tmp, out_width);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302279 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002280
2281 if (color_mode == OMAP_DSS_COLOR_RGB24U)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302282 core_clk <<= 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002283 }
2284
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302285 return core_clk;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002286}
2287
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002288static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302289 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302290{
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302291 if (height > out_height && width > out_width)
2292 return pclk * 4;
2293 else
2294 return pclk * 2;
2295}
2296
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002297static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302298 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002299{
2300 unsigned int hf, vf;
2301
2302 /*
2303 * FIXME how to determine the 'A' factor
2304 * for the no downscaling case ?
2305 */
2306
2307 if (width > 3 * out_width)
2308 hf = 4;
2309 else if (width > 2 * out_width)
2310 hf = 3;
2311 else if (width > out_width)
2312 hf = 2;
2313 else
2314 hf = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002315 if (height > out_height)
2316 vf = 2;
2317 else
2318 vf = 1;
2319
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302320 return pclk * vf * hf;
2321}
2322
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002323static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302324 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302325{
Archit Taneja8ba85302012-09-26 17:00:37 +05302326 /*
2327 * If the overlay/writeback is in mem to mem mode, there are no
2328 * downscaling limitations with respect to pixel clock, return 1 as
2329 * required core clock to represent that we have sufficient enough
2330 * core clock to do maximum downscaling
2331 */
2332 if (mem_to_mem)
2333 return 1;
2334
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302335 if (width > out_width)
2336 return DIV_ROUND_UP(pclk, out_width) * width;
2337 else
2338 return pclk;
2339}
2340
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002341static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002342 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302343 u16 width, u16 height, u16 out_width, u16 out_height,
2344 enum omap_color_mode color_mode, bool *five_taps,
2345 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302346 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302347{
2348 int error;
2349 u16 in_width, in_height;
2350 int min_factor = min(*decim_x, *decim_y);
2351 const int maxsinglelinewidth =
2352 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302353
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302354 *five_taps = false;
2355
2356 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002357 in_height = height / *decim_y;
2358 in_width = width / *decim_x;
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002359 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302360 in_height, out_width, out_height, mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302361 error = (in_width > maxsinglelinewidth || !*core_clk ||
2362 *core_clk > dispc_core_clk_rate());
2363 if (error) {
2364 if (*decim_x == *decim_y) {
2365 *decim_x = min_factor;
2366 ++*decim_y;
2367 } else {
2368 swap(*decim_x, *decim_y);
2369 if (*decim_x < *decim_y)
2370 ++*decim_x;
2371 }
2372 }
2373 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2374
Tomi Valkeinen3ce17b42015-04-10 12:48:37 +03002375 if (error) {
2376 DSSERR("failed to find scaling settings\n");
2377 return -EINVAL;
2378 }
2379
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302380 if (in_width > maxsinglelinewidth) {
2381 DSSERR("Cannot scale max input width exceeded");
2382 return -EINVAL;
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302383 }
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302384 return 0;
2385}
2386
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002387static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002388 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302389 u16 width, u16 height, u16 out_width, u16 out_height,
2390 enum omap_color_mode color_mode, bool *five_taps,
2391 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302392 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302393{
2394 int error;
2395 u16 in_width, in_height;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302396 const int maxsinglelinewidth =
2397 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2398
2399 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002400 in_height = height / *decim_y;
2401 in_width = width / *decim_x;
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002402 *five_taps = in_height > out_height;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302403
2404 if (in_width > maxsinglelinewidth)
2405 if (in_height > out_height &&
2406 in_height < out_height * 2)
2407 *five_taps = false;
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002408again:
2409 if (*five_taps)
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002410 *core_clk = calc_core_clk_five_taps(pclk, vm,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002411 in_width, in_height, out_width,
2412 out_height, color_mode);
2413 else
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002414 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302415 in_height, out_width, out_height,
2416 mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302417
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002418 error = check_horiz_timing_omap3(pclk, lclk, vm,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002419 pos_x, in_width, in_height, out_width,
2420 out_height, *five_taps);
2421 if (error && *five_taps) {
2422 *five_taps = false;
2423 goto again;
2424 }
2425
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302426 error = (error || in_width > maxsinglelinewidth * 2 ||
2427 (in_width > maxsinglelinewidth && *five_taps) ||
2428 !*core_clk || *core_clk > dispc_core_clk_rate());
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002429
2430 if (!error) {
2431 /* verify that we're inside the limits of scaler */
2432 if (in_width / 4 > out_width)
2433 error = 1;
2434
2435 if (*five_taps) {
2436 if (in_height / 4 > out_height)
2437 error = 1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302438 } else {
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002439 if (in_height / 2 > out_height)
2440 error = 1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302441 }
2442 }
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002443
Tomi Valkeinen7059e3d2015-04-10 12:48:38 +03002444 if (error)
2445 ++*decim_y;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302446 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2447
Tomi Valkeinen3ce17b42015-04-10 12:48:37 +03002448 if (error) {
2449 DSSERR("failed to find scaling settings\n");
2450 return -EINVAL;
2451 }
2452
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002453 if (check_horiz_timing_omap3(pclk, lclk, vm, pos_x, in_width,
Tomi Valkeinenf5a73482015-03-17 15:31:09 +02002454 in_height, out_width, out_height, *five_taps)) {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302455 DSSERR("horizontal timing too tight\n");
2456 return -EINVAL;
2457 }
2458
2459 if (in_width > (maxsinglelinewidth * 2)) {
2460 DSSERR("Cannot setup scaling");
2461 DSSERR("width exceeds maximum width possible");
2462 return -EINVAL;
2463 }
2464
2465 if (in_width > maxsinglelinewidth && *five_taps) {
2466 DSSERR("cannot setup scaling with five taps");
2467 return -EINVAL;
2468 }
2469 return 0;
2470}
2471
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002472static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002473 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302474 u16 width, u16 height, u16 out_width, u16 out_height,
2475 enum omap_color_mode color_mode, bool *five_taps,
2476 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302477 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302478{
2479 u16 in_width, in_width_max;
2480 int decim_x_min = *decim_x;
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002481 u16 in_height = height / *decim_y;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302482 const int maxsinglelinewidth =
2483 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
Archit Taneja8ba85302012-09-26 17:00:37 +05302484 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302485
Archit Taneja5d501082012-11-07 11:45:02 +05302486 if (mem_to_mem) {
2487 in_width_max = out_width * maxdownscale;
2488 } else {
Archit Taneja8ba85302012-09-26 17:00:37 +05302489 in_width_max = dispc_core_clk_rate() /
2490 DIV_ROUND_UP(pclk, out_width);
Archit Taneja5d501082012-11-07 11:45:02 +05302491 }
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302492
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302493 *decim_x = DIV_ROUND_UP(width, in_width_max);
2494
2495 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2496 if (*decim_x > *x_predecim)
2497 return -EINVAL;
2498
2499 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002500 in_width = width / *decim_x;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302501 } while (*decim_x <= *x_predecim &&
2502 in_width > maxsinglelinewidth && ++*decim_x);
2503
2504 if (in_width > maxsinglelinewidth) {
2505 DSSERR("Cannot scale width exceeds max line width");
2506 return -EINVAL;
2507 }
2508
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002509 *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
Archit Taneja8ba85302012-09-26 17:00:37 +05302510 out_width, out_height, mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302511 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002512}
2513
Tomi Valkeinene4c5ae72015-04-10 12:48:39 +03002514#define DIV_FRAC(dividend, divisor) \
2515 ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
2516
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002517static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302518 enum omap_overlay_caps caps,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002519 const struct videomode *vm,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302520 u16 width, u16 height, u16 out_width, u16 out_height,
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302521 enum omap_color_mode color_mode, bool *five_taps,
Chandrabhanu Mahapatrad557a9c2012-09-24 12:08:27 +05302522 int *x_predecim, int *y_predecim, u16 pos_x,
Archit Taneja8ba85302012-09-26 17:00:37 +05302523 enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302524{
Archit Taneja0373cac2011-09-08 13:25:17 +05302525 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302526 const int max_decim_limit = 16;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302527 unsigned long core_clk = 0;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302528 int decim_x, decim_y, ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302529
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002530 if (width == out_width && height == out_height)
2531 return 0;
2532
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002533 if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) {
Tomi Valkeinen4e1d3ca2014-10-03 15:14:09 +00002534 DSSERR("cannot calculate scaling settings: pclk is zero\n");
2535 return -EINVAL;
2536 }
2537
Archit Taneja5b54ed32012-09-26 16:55:27 +05302538 if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002539 return -EINVAL;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302540
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002541 if (mem_to_mem) {
Archit Taneja1c031442012-11-07 11:45:03 +05302542 *x_predecim = *y_predecim = 1;
2543 } else {
2544 *x_predecim = max_decim_limit;
2545 *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
2546 dss_has_feature(FEAT_BURST_2D)) ?
2547 2 : max_decim_limit;
2548 }
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302549
2550 if (color_mode == OMAP_DSS_COLOR_CLUT1 ||
2551 color_mode == OMAP_DSS_COLOR_CLUT2 ||
2552 color_mode == OMAP_DSS_COLOR_CLUT4 ||
2553 color_mode == OMAP_DSS_COLOR_CLUT8) {
2554 *x_predecim = 1;
2555 *y_predecim = 1;
2556 *five_taps = false;
2557 return 0;
2558 }
2559
2560 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2561 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2562
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302563 if (decim_x > *x_predecim || out_width > width * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302564 return -EINVAL;
2565
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302566 if (decim_y > *y_predecim || out_height > height * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302567 return -EINVAL;
2568
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002569 ret = dispc.feat->calc_scaling(pclk, lclk, vm, width, height,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302570 out_width, out_height, color_mode, five_taps,
Archit Taneja8ba85302012-09-26 17:00:37 +05302571 x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
2572 mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302573 if (ret)
2574 return ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302575
Tomi Valkeinene4c5ae72015-04-10 12:48:39 +03002576 DSSDBG("%dx%d -> %dx%d (%d.%02d x %d.%02d), decim %dx%d %dx%d (%d.%02d x %d.%02d), taps %d, req clk %lu, cur clk %lu\n",
2577 width, height,
2578 out_width, out_height,
2579 out_width / width, DIV_FRAC(out_width, width),
2580 out_height / height, DIV_FRAC(out_height, height),
2581
2582 decim_x, decim_y,
2583 width / decim_x, height / decim_y,
2584 out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
2585 out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
2586
2587 *five_taps ? 5 : 3,
2588 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302589
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302590 if (!core_clk || core_clk > dispc_core_clk_rate()) {
Archit Taneja79ad75f2011-09-08 13:15:11 +05302591 DSSERR("failed to set up scaling, "
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302592 "required core clk rate = %lu Hz, "
2593 "current core clk rate = %lu Hz\n",
2594 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302595 return -EINVAL;
2596 }
2597
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302598 *x_predecim = decim_x;
2599 *y_predecim = decim_y;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302600 return 0;
2601}
2602
Archit Taneja84a880f2012-09-26 16:57:37 +05302603static int dispc_ovl_setup_common(enum omap_plane plane,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302604 enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
2605 u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
2606 u16 out_width, u16 out_height, enum omap_color_mode color_mode,
2607 u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
2608 u8 global_alpha, enum omap_dss_rotation_type rotation_type,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002609 bool replication, const struct videomode *vm,
Archit Taneja8ba85302012-09-26 17:00:37 +05302610 bool mem_to_mem)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002611{
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302612 bool five_taps = true;
Peter Senna Tschudin62a83182013-09-22 20:44:11 +02002613 bool fieldmode = false;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302614 int r, cconv = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002615 unsigned offset0, offset1;
2616 s32 row_inc;
2617 s32 pix_inc;
Archit Taneja6be0d732012-11-07 11:45:04 +05302618 u16 frame_width, frame_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002619 unsigned int field_offset = 0;
Archit Taneja84a880f2012-09-26 16:57:37 +05302620 u16 in_height = height;
2621 u16 in_width = width;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302622 int x_predecim = 1, y_predecim = 1;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002623 bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED);
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002624 unsigned long pclk = dispc_plane_pclk_rate(plane);
2625 unsigned long lclk = dispc_plane_lclk_rate(plane);
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02002626
Tomi Valkeinene5666582014-11-28 14:34:15 +02002627 if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002628 return -EINVAL;
2629
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002630 switch (color_mode) {
2631 case OMAP_DSS_COLOR_YUV2:
2632 case OMAP_DSS_COLOR_UYVY:
2633 case OMAP_DSS_COLOR_NV12:
2634 if (in_width & 1) {
2635 DSSERR("input width %d is not even for YUV format\n",
2636 in_width);
2637 return -EINVAL;
2638 }
2639 break;
2640
2641 default:
2642 break;
2643 }
2644
Archit Taneja84a880f2012-09-26 16:57:37 +05302645 out_width = out_width == 0 ? width : out_width;
2646 out_height = out_height == 0 ? height : out_height;
Tomi Valkeinencf073662011-11-03 16:08:27 +02002647
Archit Taneja84a880f2012-09-26 16:57:37 +05302648 if (ilace && height == out_height)
Peter Senna Tschudin62a83182013-09-22 20:44:11 +02002649 fieldmode = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002650
2651 if (ilace) {
2652 if (fieldmode)
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302653 in_height /= 2;
Archit Taneja8eeb7012012-08-22 12:33:49 +05302654 pos_y /= 2;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302655 out_height /= 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002656
2657 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
Archit Taneja84a880f2012-09-26 16:57:37 +05302658 "out_height %d\n", in_height, pos_y,
2659 out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002660 }
2661
Archit Taneja84a880f2012-09-26 16:57:37 +05302662 if (!dss_feat_color_mode_supported(plane, color_mode))
Archit Taneja8dad2ab2010-11-25 17:58:10 +05302663 return -EINVAL;
2664
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002665 r = dispc_ovl_calc_scaling(pclk, lclk, caps, vm, in_width,
Archit Taneja84a880f2012-09-26 16:57:37 +05302666 in_height, out_width, out_height, color_mode,
2667 &five_taps, &x_predecim, &y_predecim, pos_x,
Archit Taneja8ba85302012-09-26 17:00:37 +05302668 rotation_type, mem_to_mem);
Archit Taneja79ad75f2011-09-08 13:15:11 +05302669 if (r)
2670 return r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002671
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002672 in_width = in_width / x_predecim;
2673 in_height = in_height / y_predecim;
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302674
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002675 if (x_predecim > 1 || y_predecim > 1)
2676 DSSDBG("predecimation %d x %x, new input size %d x %d\n",
2677 x_predecim, y_predecim, in_width, in_height);
2678
2679 switch (color_mode) {
2680 case OMAP_DSS_COLOR_YUV2:
2681 case OMAP_DSS_COLOR_UYVY:
2682 case OMAP_DSS_COLOR_NV12:
2683 if (in_width & 1) {
2684 DSSDBG("predecimated input width is not even for YUV format\n");
2685 DSSDBG("adjusting input width %d -> %d\n",
2686 in_width, in_width & ~1);
2687
2688 in_width &= ~1;
2689 }
2690 break;
2691
2692 default:
2693 break;
2694 }
2695
Archit Taneja84a880f2012-09-26 16:57:37 +05302696 if (color_mode == OMAP_DSS_COLOR_YUV2 ||
2697 color_mode == OMAP_DSS_COLOR_UYVY ||
2698 color_mode == OMAP_DSS_COLOR_NV12)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302699 cconv = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002700
2701 if (ilace && !fieldmode) {
2702 /*
2703 * when downscaling the bottom field may have to start several
2704 * source lines below the top field. Unfortunately ACCUI
2705 * registers will only hold the fractional part of the offset
2706 * so the integer part must be added to the base address of the
2707 * bottom field.
2708 */
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302709 if (!in_height || in_height == out_height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002710 field_offset = 0;
2711 else
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302712 field_offset = in_height / out_height / 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002713 }
2714
2715 /* Fields are independent but interleaved in memory. */
2716 if (fieldmode)
2717 field_offset = 1;
2718
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002719 offset0 = 0;
2720 offset1 = 0;
2721 row_inc = 0;
2722 pix_inc = 0;
2723
Archit Taneja6be0d732012-11-07 11:45:04 +05302724 if (plane == OMAP_DSS_WB) {
2725 frame_width = out_width;
2726 frame_height = out_height;
2727 } else {
2728 frame_width = in_width;
2729 frame_height = height;
2730 }
2731
Archit Taneja84a880f2012-09-26 16:57:37 +05302732 if (rotation_type == OMAP_DSS_ROT_TILER)
Archit Taneja6be0d732012-11-07 11:45:04 +05302733 calc_tiler_rotation_offset(screen_width, frame_width,
Archit Taneja84a880f2012-09-26 16:57:37 +05302734 color_mode, fieldmode, field_offset,
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302735 &offset0, &offset1, &row_inc, &pix_inc,
2736 x_predecim, y_predecim);
Archit Taneja84a880f2012-09-26 16:57:37 +05302737 else if (rotation_type == OMAP_DSS_ROT_DMA)
Archit Taneja6be0d732012-11-07 11:45:04 +05302738 calc_dma_rotation_offset(rotation, mirror, screen_width,
2739 frame_width, frame_height,
Archit Taneja84a880f2012-09-26 16:57:37 +05302740 color_mode, fieldmode, field_offset,
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302741 &offset0, &offset1, &row_inc, &pix_inc,
2742 x_predecim, y_predecim);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002743 else
Archit Taneja84a880f2012-09-26 16:57:37 +05302744 calc_vrfb_rotation_offset(rotation, mirror,
Archit Taneja6be0d732012-11-07 11:45:04 +05302745 screen_width, frame_width, frame_height,
Archit Taneja84a880f2012-09-26 16:57:37 +05302746 color_mode, fieldmode, field_offset,
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302747 &offset0, &offset1, &row_inc, &pix_inc,
2748 x_predecim, y_predecim);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002749
2750 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2751 offset0, offset1, row_inc, pix_inc);
2752
Archit Taneja84a880f2012-09-26 16:57:37 +05302753 dispc_ovl_set_color_mode(plane, color_mode);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002754
Archit Taneja84a880f2012-09-26 16:57:37 +05302755 dispc_ovl_configure_burst_type(plane, rotation_type);
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302756
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02002757 if (dispc.feat->reverse_ilace_field_order)
2758 swap(offset0, offset1);
2759
Archit Taneja84a880f2012-09-26 16:57:37 +05302760 dispc_ovl_set_ba0(plane, paddr + offset0);
2761 dispc_ovl_set_ba1(plane, paddr + offset1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002762
Archit Taneja84a880f2012-09-26 16:57:37 +05302763 if (OMAP_DSS_COLOR_NV12 == color_mode) {
2764 dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
2765 dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
Amber Jain0d66cbb2011-05-19 19:47:54 +05302766 }
2767
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03002768 if (dispc.feat->last_pixel_inc_missing)
2769 row_inc += pix_inc - 1;
2770
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002771 dispc_ovl_set_row_inc(plane, row_inc);
2772 dispc_ovl_set_pix_inc(plane, pix_inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002773
Archit Taneja84a880f2012-09-26 16:57:37 +05302774 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302775 in_height, out_width, out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002776
Archit Taneja84a880f2012-09-26 16:57:37 +05302777 dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002778
Archit Taneja78b687f2012-09-21 14:51:49 +05302779 dispc_ovl_set_input_size(plane, in_width, in_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002780
Archit Taneja5b54ed32012-09-26 16:55:27 +05302781 if (caps & OMAP_DSS_OVL_CAP_SCALE) {
Chandrabhanu Mahapatraaed74b52012-04-02 20:43:16 +05302782 dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2783 out_height, ilace, five_taps, fieldmode,
Archit Taneja84a880f2012-09-26 16:57:37 +05302784 color_mode, rotation);
Archit Taneja78b687f2012-09-21 14:51:49 +05302785 dispc_ovl_set_output_size(plane, out_width, out_height);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002786 dispc_ovl_set_vid_color_conv(plane, cconv);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002787 }
2788
Archit Tanejac35eeb22013-03-26 19:15:24 +05302789 dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
2790 color_mode);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002791
Archit Taneja84a880f2012-09-26 16:57:37 +05302792 dispc_ovl_set_zorder(plane, caps, zorder);
2793 dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
2794 dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002795
Archit Tanejad79db852012-09-22 12:30:17 +05302796 dispc_ovl_enable_replication(plane, caps, replication);
Archit Tanejac3d925292011-09-14 11:52:54 +05302797
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002798 return 0;
2799}
2800
Archit Taneja84a880f2012-09-26 16:57:37 +05302801int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002802 bool replication, const struct videomode *vm,
Archit Taneja8ba85302012-09-26 17:00:37 +05302803 bool mem_to_mem)
Archit Taneja84a880f2012-09-26 16:57:37 +05302804{
2805 int r;
Tomi Valkeinen16bf20c2012-10-15 15:33:22 +03002806 enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
Archit Taneja84a880f2012-09-26 16:57:37 +05302807 enum omap_channel channel;
2808
2809 channel = dispc_ovl_get_channel_out(plane);
2810
Arnd Bergmann24f13a62014-04-24 13:28:18 +01002811 DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
2812 " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
2813 plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
Archit Taneja84a880f2012-09-26 16:57:37 +05302814 oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
2815 oi->color_mode, oi->rotation, oi->mirror, channel, replication);
2816
Tomi Valkeinen16bf20c2012-10-15 15:33:22 +03002817 r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302818 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
2819 oi->out_width, oi->out_height, oi->color_mode, oi->rotation,
2820 oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002821 oi->rotation_type, replication, vm, mem_to_mem);
Archit Taneja84a880f2012-09-26 16:57:37 +05302822
2823 return r;
2824}
Tomi Valkeinen348be692012-11-07 18:17:35 +02002825EXPORT_SYMBOL(dispc_ovl_setup);
Archit Taneja84a880f2012-09-26 16:57:37 +05302826
Archit Taneja749feff2012-08-31 12:32:52 +05302827int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002828 bool mem_to_mem, const struct videomode *vm)
Archit Taneja749feff2012-08-31 12:32:52 +05302829{
2830 int r;
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302831 u32 l;
Archit Taneja749feff2012-08-31 12:32:52 +05302832 enum omap_plane plane = OMAP_DSS_WB;
2833 const int pos_x = 0, pos_y = 0;
2834 const u8 zorder = 0, global_alpha = 0;
2835 const bool replication = false;
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302836 bool truncation;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002837 int in_width = vm->hactive;
2838 int in_height = vm->vactive;
Archit Taneja749feff2012-08-31 12:32:52 +05302839 enum omap_overlay_caps caps =
2840 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
2841
2842 DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
2843 "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
2844 in_height, wi->width, wi->height, wi->color_mode, wi->rotation,
2845 wi->mirror);
2846
2847 r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
2848 wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
2849 wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder,
2850 wi->pre_mult_alpha, global_alpha, wi->rotation_type,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002851 replication, vm, mem_to_mem);
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302852
2853 switch (wi->color_mode) {
2854 case OMAP_DSS_COLOR_RGB16:
2855 case OMAP_DSS_COLOR_RGB24P:
2856 case OMAP_DSS_COLOR_ARGB16:
2857 case OMAP_DSS_COLOR_RGBA16:
2858 case OMAP_DSS_COLOR_RGB12U:
2859 case OMAP_DSS_COLOR_ARGB16_1555:
2860 case OMAP_DSS_COLOR_XRGB16_1555:
2861 case OMAP_DSS_COLOR_RGBX16:
2862 truncation = true;
2863 break;
2864 default:
2865 truncation = false;
2866 break;
2867 }
2868
2869 /* setup extra DISPC_WB_ATTRIBUTES */
2870 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
2871 l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
2872 l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
Tomi Valkeinen4c055ce2015-11-04 17:10:53 +02002873 if (mem_to_mem)
2874 l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002875 else
2876 l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302877 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Archit Taneja749feff2012-08-31 12:32:52 +05302878
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002879 if (mem_to_mem) {
2880 /* WBDELAYCOUNT */
2881 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
2882 } else {
2883 int wbdelay;
2884
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002885 wbdelay = min(vm->vfront_porch +
2886 vm->vsync_len + vm->vback_porch, (u32)255);
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002887
2888 /* WBDELAYCOUNT */
2889 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
2890 }
2891
Archit Taneja749feff2012-08-31 12:32:52 +05302892 return r;
2893}
2894
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002895int dispc_ovl_enable(enum omap_plane plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002896{
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002897 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2898
Archit Taneja9b372c22011-05-06 11:45:49 +05302899 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002900
2901 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002902}
Tomi Valkeinen348be692012-11-07 18:17:35 +02002903EXPORT_SYMBOL(dispc_ovl_enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002904
Tomi Valkeinen04bd8ac2012-10-10 14:13:15 +03002905bool dispc_ovl_enabled(enum omap_plane plane)
2906{
2907 return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0);
2908}
Tomi Valkeinen348be692012-11-07 18:17:35 +02002909EXPORT_SYMBOL(dispc_ovl_enabled);
Tomi Valkeinen04bd8ac2012-10-10 14:13:15 +03002910
Tomi Valkeinen7b9cb5e2015-11-04 15:11:25 +02002911enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel)
2912{
2913 return dss_feat_get_supported_outputs(channel);
2914}
2915EXPORT_SYMBOL(dispc_mgr_get_supported_outputs);
2916
Archit Taneja0b23e5b2012-09-22 12:39:33 +05302917void dispc_wb_enable(bool enable)
2918{
Tomi Valkeinen916188a2012-10-10 14:13:26 +03002919 dispc_ovl_enable(OMAP_DSS_WB, enable);
Archit Taneja0b23e5b2012-09-22 12:39:33 +05302920}
2921
2922bool dispc_wb_is_enabled(void)
2923{
Tomi Valkeinen916188a2012-10-10 14:13:26 +03002924 return dispc_ovl_enabled(OMAP_DSS_WB);
Archit Taneja0b23e5b2012-09-22 12:39:33 +05302925}
2926
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002927static void dispc_lcd_enable_signal_polarity(bool act_high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002928{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002929 if (!dss_has_feature(FEAT_LCDENABLEPOL))
2930 return;
2931
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002932 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002933}
2934
2935void dispc_lcd_enable_signal(bool enable)
2936{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002937 if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
2938 return;
2939
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002940 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002941}
2942
2943void dispc_pck_free_enable(bool enable)
2944{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002945 if (!dss_has_feature(FEAT_PCKFREEENABLE))
2946 return;
2947
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002948 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002949}
2950
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002951static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002952{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302953 mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002954}
2955
2956
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002957static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002958{
Archit Tanejad21f43b2012-06-21 09:45:11 +05302959 mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002960}
2961
Tomi Valkeinen65904152015-11-04 17:10:57 +02002962static void dispc_set_loadmode(enum omap_dss_load_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002963{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002964 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002965}
2966
2967
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002968static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002969{
Sumit Semwal8613b002010-12-02 11:27:09 +00002970 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002971}
2972
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002973static void dispc_mgr_set_trans_key(enum omap_channel ch,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002974 enum omap_dss_trans_key_type type,
2975 u32 trans_key)
2976{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302977 mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002978
Sumit Semwal8613b002010-12-02 11:27:09 +00002979 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002980}
2981
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002982static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002983{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302984 mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002985}
Archit Taneja11354dd2011-09-26 11:47:29 +05302986
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002987static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2988 bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002989{
Archit Taneja11354dd2011-09-26 11:47:29 +05302990 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002991 return;
2992
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002993 if (ch == OMAP_DSS_CHANNEL_LCD)
2994 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
Sumit Semwal2a205f32010-12-02 11:27:12 +00002995 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002996 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002997}
Archit Taneja11354dd2011-09-26 11:47:29 +05302998
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002999void dispc_mgr_setup(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02003000 const struct omap_overlay_manager_info *info)
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02003001{
3002 dispc_mgr_set_default_color(channel, info->default_color);
3003 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
3004 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
3005 dispc_mgr_enable_alpha_fixed_zorder(channel,
3006 info->partial_alpha_enabled);
3007 if (dss_has_feature(FEAT_CPR)) {
3008 dispc_mgr_enable_cpr(channel, info->cpr_enable);
3009 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
3010 }
3011}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003012EXPORT_SYMBOL(dispc_mgr_setup);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003013
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03003014static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003015{
3016 int code;
3017
3018 switch (data_lines) {
3019 case 12:
3020 code = 0;
3021 break;
3022 case 16:
3023 code = 1;
3024 break;
3025 case 18:
3026 code = 2;
3027 break;
3028 case 24:
3029 code = 3;
3030 break;
3031 default:
3032 BUG();
3033 return;
3034 }
3035
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05303036 mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003037}
3038
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03003039static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003040{
3041 u32 l;
Archit Taneja569969d2011-08-22 17:41:57 +05303042 int gpout0, gpout1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003043
3044 switch (mode) {
Archit Taneja569969d2011-08-22 17:41:57 +05303045 case DSS_IO_PAD_MODE_RESET:
3046 gpout0 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003047 gpout1 = 0;
3048 break;
Archit Taneja569969d2011-08-22 17:41:57 +05303049 case DSS_IO_PAD_MODE_RFBI:
3050 gpout0 = 1;
3051 gpout1 = 0;
3052 break;
3053 case DSS_IO_PAD_MODE_BYPASS:
3054 gpout0 = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003055 gpout1 = 1;
3056 break;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003057 default:
3058 BUG();
3059 return;
3060 }
3061
Archit Taneja569969d2011-08-22 17:41:57 +05303062 l = dispc_read_reg(DISPC_CONTROL);
3063 l = FLD_MOD(l, gpout0, 15, 15);
3064 l = FLD_MOD(l, gpout1, 16, 16);
3065 dispc_write_reg(DISPC_CONTROL, l);
3066}
3067
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03003068static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
Archit Taneja569969d2011-08-22 17:41:57 +05303069{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05303070 mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003071}
3072
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03003073void dispc_mgr_set_lcd_config(enum omap_channel channel,
3074 const struct dss_lcd_mgr_config *config)
3075{
3076 dispc_mgr_set_io_pad_mode(config->io_pad_mode);
3077
3078 dispc_mgr_enable_stallmode(channel, config->stallmode);
3079 dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck);
3080
3081 dispc_mgr_set_clock_div(channel, &config->clock_info);
3082
3083 dispc_mgr_set_tft_data_lines(channel, config->video_port_width);
3084
3085 dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity);
3086
3087 dispc_mgr_set_lcd_type_tft(channel);
3088}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003089EXPORT_SYMBOL(dispc_mgr_set_lcd_config);
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03003090
Archit Taneja8f366162012-04-16 12:53:44 +05303091static bool _dispc_mgr_size_ok(u16 width, u16 height)
3092{
Archit Taneja33b89922012-11-14 13:50:15 +05303093 return width <= dispc.feat->mgr_width_max &&
3094 height <= dispc.feat->mgr_height_max;
Archit Taneja8f366162012-04-16 12:53:44 +05303095}
3096
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03003097static bool _dispc_lcd_timings_ok(int hsync_len, int hfp, int hbp,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003098 int vsw, int vfp, int vbp)
3099{
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03003100 if (hsync_len < 1 || hsync_len > dispc.feat->sw_max ||
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303101 hfp < 1 || hfp > dispc.feat->hp_max ||
3102 hbp < 1 || hbp > dispc.feat->hp_max ||
3103 vsw < 1 || vsw > dispc.feat->sw_max ||
3104 vfp < 0 || vfp > dispc.feat->vp_max ||
3105 vbp < 0 || vbp > dispc.feat->vp_max)
3106 return false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003107 return true;
3108}
3109
Archit Tanejaca5ca692013-03-26 19:15:22 +05303110static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
3111 unsigned long pclk)
3112{
3113 if (dss_mgr_is_lcd(channel))
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05003114 return pclk <= dispc.feat->max_lcd_pclk;
Archit Tanejaca5ca692013-03-26 19:15:22 +05303115 else
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05003116 return pclk <= dispc.feat->max_tv_pclk;
Archit Tanejaca5ca692013-03-26 19:15:22 +05303117}
3118
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003119bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003120{
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003121 if (!_dispc_mgr_size_ok(vm->hactive, vm->vactive))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03003122 return false;
Archit Taneja8f366162012-04-16 12:53:44 +05303123
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003124 if (!_dispc_mgr_pclk_ok(channel, vm->pixelclock))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03003125 return false;
Archit Tanejaca5ca692013-03-26 19:15:22 +05303126
3127 if (dss_mgr_is_lcd(channel)) {
Tomi Valkeinenbeb83842014-06-05 11:35:10 +03003128 /* TODO: OMAP4+ supports interlace for LCD outputs */
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003129 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03003130 return false;
Tomi Valkeinenbeb83842014-06-05 11:35:10 +03003131
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003132 if (!_dispc_lcd_timings_ok(vm->hsync_len,
3133 vm->hfront_porch, vm->hback_porch,
3134 vm->vsync_len, vm->vfront_porch,
3135 vm->vback_porch))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03003136 return false;
Archit Tanejaca5ca692013-03-26 19:15:22 +05303137 }
Archit Taneja8f366162012-04-16 12:53:44 +05303138
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03003139 return true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003140}
3141
Peter Ujfalusi3b592932016-09-22 14:06:56 +03003142static void _dispc_mgr_set_lcd_timings(enum omap_channel channel,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003143 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003144{
Archit Taneja655e2942012-06-21 10:37:43 +05303145 u32 timing_h, timing_v, l;
Tomi Valkeinened351882014-10-02 17:58:49 +00003146 bool onoff, rf, ipc, vs, hs, de;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003147
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003148 timing_h = FLD_VAL(vm->hsync_len - 1, dispc.feat->sw_start, 0) |
3149 FLD_VAL(vm->hfront_porch - 1, dispc.feat->fp_start, 8) |
3150 FLD_VAL(vm->hback_porch - 1, dispc.feat->bp_start, 20);
3151 timing_v = FLD_VAL(vm->vsync_len - 1, dispc.feat->sw_start, 0) |
3152 FLD_VAL(vm->vfront_porch, dispc.feat->fp_start, 8) |
3153 FLD_VAL(vm->vback_porch, dispc.feat->bp_start, 20);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003154
Sumit Semwal64ba4f72010-12-02 11:27:10 +00003155 dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
3156 dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
Archit Taneja655e2942012-06-21 10:37:43 +05303157
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003158 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00003159 vs = false;
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03003160 else
3161 vs = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00003162
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003163 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00003164 hs = false;
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03003165 else
3166 hs = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00003167
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003168 if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00003169 de = false;
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +03003170 else
3171 de = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00003172
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003173 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
Archit Taneja655e2942012-06-21 10:37:43 +05303174 ipc = false;
Peter Ujfalusif149e172016-09-22 14:07:00 +03003175 else
Archit Taneja655e2942012-06-21 10:37:43 +05303176 ipc = true;
Archit Taneja655e2942012-06-21 10:37:43 +05303177
Tomi Valkeinen7a163602014-10-02 17:58:48 +00003178 /* always use the 'rf' setting */
3179 onoff = true;
3180
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003181 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
Archit Taneja655e2942012-06-21 10:37:43 +05303182 rf = true;
Peter Ujfalusid34afb72016-09-22 14:07:01 +03003183 else
3184 rf = false;
Archit Taneja655e2942012-06-21 10:37:43 +05303185
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03003186 l = FLD_VAL(onoff, 17, 17) |
3187 FLD_VAL(rf, 16, 16) |
Tomi Valkeinened351882014-10-02 17:58:49 +00003188 FLD_VAL(de, 15, 15) |
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03003189 FLD_VAL(ipc, 14, 14) |
Tomi Valkeinened351882014-10-02 17:58:49 +00003190 FLD_VAL(hs, 13, 13) |
3191 FLD_VAL(vs, 12, 12);
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03003192
Tomi Valkeinene5f80912015-10-21 13:08:59 +03003193 /* always set ALIGN bit when available */
3194 if (dispc.feat->supports_sync_align)
3195 l |= (1 << 18);
3196
Archit Taneja655e2942012-06-21 10:37:43 +05303197 dispc_write_reg(DISPC_POL_FREQ(channel), l);
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00003198
3199 if (dispc.syscon_pol) {
3200 const int shifts[] = {
3201 [OMAP_DSS_CHANNEL_LCD] = 0,
3202 [OMAP_DSS_CHANNEL_LCD2] = 1,
3203 [OMAP_DSS_CHANNEL_LCD3] = 2,
3204 };
3205
3206 u32 mask, val;
3207
3208 mask = (1 << 0) | (1 << 3) | (1 << 6);
3209 val = (rf << 0) | (ipc << 3) | (onoff << 6);
3210
3211 mask <<= 16 + shifts[channel];
3212 val <<= 16 + shifts[channel];
3213
3214 regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
3215 mask, val);
3216 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003217}
3218
3219/* change name to mode? */
Archit Tanejac51d9212012-04-16 12:53:43 +05303220void dispc_mgr_set_timings(enum omap_channel channel,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003221 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003222{
3223 unsigned xtot, ytot;
3224 unsigned long ht, vt;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003225 struct videomode t = *vm;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003226
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003227 DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
Archit Tanejac51d9212012-04-16 12:53:43 +05303228
Archit Taneja2aefad42012-05-18 14:36:54 +05303229 if (!dispc_mgr_timings_ok(channel, &t)) {
Archit Taneja8f366162012-04-16 12:53:44 +05303230 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03003231 return;
3232 }
Archit Tanejac51d9212012-04-16 12:53:43 +05303233
Archit Tanejadd88b7a2012-06-29 14:41:30 +05303234 if (dss_mgr_is_lcd(channel)) {
Peter Ujfalusi3b592932016-09-22 14:06:56 +03003235 _dispc_mgr_set_lcd_timings(channel, &t);
Archit Tanejac51d9212012-04-16 12:53:43 +05303236
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03003237 xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch;
Peter Ujfalusi458540c2016-09-22 14:06:53 +03003238 ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch;
Archit Tanejac51d9212012-04-16 12:53:43 +05303239
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003240 ht = vm->pixelclock / xtot;
3241 vt = vm->pixelclock / xtot / ytot;
Archit Tanejac51d9212012-04-16 12:53:43 +05303242
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003243 DSSDBG("pck %lu\n", vm->pixelclock);
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03003244 DSSDBG("hsync_len %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03003245 t.hsync_len, t.hfront_porch, t.hback_porch,
Peter Ujfalusi458540c2016-09-22 14:06:53 +03003246 t.vsync_len, t.vfront_porch, t.vback_porch);
Archit Taneja655e2942012-06-21 10:37:43 +05303247 DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03003248 !!(t.flags & DISPLAY_FLAGS_VSYNC_HIGH),
3249 !!(t.flags & DISPLAY_FLAGS_HSYNC_HIGH),
Peter Ujfalusif149e172016-09-22 14:07:00 +03003250 !!(t.flags & DISPLAY_FLAGS_PIXDATA_POSEDGE),
3251 !!(t.flags & DISPLAY_FLAGS_DE_HIGH),
Peter Ujfalusid34afb72016-09-22 14:07:01 +03003252 !!(t.flags & DISPLAY_FLAGS_SYNC_POSEDGE));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003253
Archit Tanejac51d9212012-04-16 12:53:43 +05303254 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
Archit Taneja2aefad42012-05-18 14:36:54 +05303255 } else {
Peter Ujfalusi53058292016-09-22 14:06:55 +03003256 if (t.flags & DISPLAY_FLAGS_INTERLACED)
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003257 t.vactive /= 2;
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02003258
3259 if (dispc.feat->supports_double_pixel)
Peter Ujfalusi531efb32016-09-22 14:06:59 +03003260 REG_FLD_MOD(DISPC_CONTROL,
3261 !!(t.flags & DISPLAY_FLAGS_DOUBLECLK),
3262 19, 17);
Archit Tanejac51d9212012-04-16 12:53:43 +05303263 }
Archit Taneja8f366162012-04-16 12:53:44 +05303264
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003265 dispc_mgr_set_size(channel, t.hactive, t.vactive);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003266}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003267EXPORT_SYMBOL(dispc_mgr_set_timings);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003268
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003269static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
Sumit Semwalff1b2cde2010-12-02 11:27:11 +00003270 u16 pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003271{
3272 BUG_ON(lck_div < 1);
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003273 BUG_ON(pck_div < 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003274
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003275 dispc_write_reg(DISPC_DIVISORo(channel),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003276 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003277
Luis de Bethencourt0bcfdba2015-10-15 13:29:38 +01003278 if (!dss_has_feature(FEAT_CORE_CLK_DIV) &&
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003279 channel == OMAP_DSS_CHANNEL_LCD)
3280 dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003281}
3282
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003283static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
Sumit Semwal2a205f32010-12-02 11:27:12 +00003284 int *pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003285{
3286 u32 l;
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003287 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003288 *lck_div = FLD_GET(l, 23, 16);
3289 *pck_div = FLD_GET(l, 7, 0);
3290}
3291
Tomi Valkeinen65904152015-11-04 17:10:57 +02003292static unsigned long dispc_fclk_rate(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003293{
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003294 unsigned long r;
3295 enum dss_clk_source src;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003296
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003297 src = dss_get_dispc_clk_source();
3298
3299 if (src == DSS_CLK_SRC_FCK) {
Tomi Valkeinen5aaee692012-12-12 10:37:03 +02003300 r = dss_get_dispc_clk_rate();
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003301 } else {
3302 struct dss_pll *pll;
3303 unsigned clkout_idx;
Tomi Valkeinen93550922014-12-31 11:25:48 +02003304
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003305 pll = dss_pll_find_by_src(src);
3306 clkout_idx = dss_pll_get_clkout_idx_for_src(src);
Tomi Valkeinen93550922014-12-31 11:25:48 +02003307
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003308 r = pll->cinfo.clkout[clkout_idx];
Taneja, Archit66534e82011-03-08 05:50:34 -06003309 }
3310
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003311 return r;
3312}
3313
Tomi Valkeinen65904152015-11-04 17:10:57 +02003314static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003315{
3316 int lcd;
3317 unsigned long r;
Tomi Valkeinen01575772016-05-17 16:08:34 +03003318 enum dss_clk_source src;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003319
Tomi Valkeinen01575772016-05-17 16:08:34 +03003320 /* for TV, LCLK rate is the FCLK rate */
3321 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003322 return dispc_fclk_rate();
Tomi Valkeinen01575772016-05-17 16:08:34 +03003323
3324 src = dss_get_lcd_clk_source(channel);
3325
3326 if (src == DSS_CLK_SRC_FCK) {
3327 r = dss_get_dispc_clk_rate();
3328 } else {
3329 struct dss_pll *pll;
3330 unsigned clkout_idx;
3331
3332 pll = dss_pll_find_by_src(src);
3333 clkout_idx = dss_pll_get_clkout_idx_for_src(src);
3334
3335 r = pll->cinfo.clkout[clkout_idx];
Taneja, Architea751592011-03-08 05:50:35 -06003336 }
Tomi Valkeinen01575772016-05-17 16:08:34 +03003337
3338 lcd = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3339
3340 return r / lcd;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003341}
3342
Tomi Valkeinen65904152015-11-04 17:10:57 +02003343static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003344{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003345 unsigned long r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003346
Archit Tanejadd88b7a2012-06-29 14:41:30 +05303347 if (dss_mgr_is_lcd(channel)) {
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303348 int pcd;
3349 u32 l;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003350
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303351 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003352
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303353 pcd = FLD_GET(l, 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003354
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303355 r = dispc_mgr_lclk_rate(channel);
3356
3357 return r / pcd;
3358 } else {
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003359 return dispc.tv_pclk_rate;
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303360 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003361}
3362
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003363void dispc_set_tv_pclk(unsigned long pclk)
3364{
3365 dispc.tv_pclk_rate = pclk;
3366}
3367
Tomi Valkeinen65904152015-11-04 17:10:57 +02003368static unsigned long dispc_core_clk_rate(void)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05303369{
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003370 return dispc.core_clk_rate;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05303371}
3372
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303373static unsigned long dispc_plane_pclk_rate(enum omap_plane plane)
3374{
Tomi Valkeinen251886d2012-11-15 13:20:02 +02003375 enum omap_channel channel;
3376
3377 if (plane == OMAP_DSS_WB)
3378 return 0;
3379
3380 channel = dispc_ovl_get_channel_out(plane);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303381
3382 return dispc_mgr_pclk_rate(channel);
3383}
3384
3385static unsigned long dispc_plane_lclk_rate(enum omap_plane plane)
3386{
Tomi Valkeinen251886d2012-11-15 13:20:02 +02003387 enum omap_channel channel;
3388
3389 if (plane == OMAP_DSS_WB)
3390 return 0;
3391
3392 channel = dispc_ovl_get_channel_out(plane);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303393
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003394 return dispc_mgr_lclk_rate(channel);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303395}
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003396
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303397static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003398{
3399 int lcd, pcd;
Tomi Valkeinendc0352d2016-05-17 13:45:09 +03003400 enum dss_clk_source lcd_clk_src;
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303401
3402 seq_printf(s, "- %s -\n", mgr_desc[channel].name);
3403
3404 lcd_clk_src = dss_get_lcd_clk_source(channel);
3405
Tomi Valkeinen557a1542016-05-17 13:49:18 +03003406 seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name,
Tomi Valkeinen407bd562016-05-17 13:50:55 +03003407 dss_get_clk_source_name(lcd_clk_src));
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303408
3409 dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
3410
3411 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3412 dispc_mgr_lclk_rate(channel), lcd);
3413 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
3414 dispc_mgr_pclk_rate(channel), pcd);
3415}
3416
3417void dispc_dump_clocks(struct seq_file *s)
3418{
3419 int lcd;
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003420 u32 l;
Tomi Valkeinendc0352d2016-05-17 13:45:09 +03003421 enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003422
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003423 if (dispc_runtime_get())
3424 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003425
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003426 seq_printf(s, "- DISPC -\n");
3427
Tomi Valkeinen557a1542016-05-17 13:49:18 +03003428 seq_printf(s, "dispc fclk source = %s\n",
Tomi Valkeinen407bd562016-05-17 13:50:55 +03003429 dss_get_clk_source_name(dispc_clk_src));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003430
3431 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
Sumit Semwal2a205f32010-12-02 11:27:12 +00003432
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003433 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3434 seq_printf(s, "- DISPC-CORE-CLK -\n");
3435 l = dispc_read_reg(DISPC_DIVISOR);
3436 lcd = FLD_GET(l, 23, 16);
3437
3438 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3439 (dispc_fclk_rate()/lcd), lcd);
3440 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003441
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303442 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
Taneja, Architea751592011-03-08 05:50:35 -06003443
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303444 if (dss_has_feature(FEAT_MGR_LCD2))
3445 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
3446 if (dss_has_feature(FEAT_MGR_LCD3))
3447 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003448
3449 dispc_runtime_put();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003450}
3451
Tomi Valkeinene40402c2012-03-02 18:01:07 +02003452static void dispc_dump_regs(struct seq_file *s)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003453{
Archit Taneja4dd2da12011-08-05 19:06:01 +05303454 int i, j;
3455 const char *mgr_names[] = {
3456 [OMAP_DSS_CHANNEL_LCD] = "LCD",
3457 [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3458 [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303459 [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303460 };
3461 const char *ovl_names[] = {
3462 [OMAP_DSS_GFX] = "GFX",
3463 [OMAP_DSS_VIDEO1] = "VID1",
3464 [OMAP_DSS_VIDEO2] = "VID2",
Archit Tanejab8c095b2011-09-13 18:20:33 +05303465 [OMAP_DSS_VIDEO3] = "VID3",
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003466 [OMAP_DSS_WB] = "WB",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303467 };
3468 const char **p_names;
3469
Archit Taneja9b372c22011-05-06 11:45:49 +05303470#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003471
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003472 if (dispc_runtime_get())
3473 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003474
Archit Taneja5010be82011-08-05 19:06:00 +05303475 /* DISPC common registers */
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003476 DUMPREG(DISPC_REVISION);
3477 DUMPREG(DISPC_SYSCONFIG);
3478 DUMPREG(DISPC_SYSSTATUS);
3479 DUMPREG(DISPC_IRQSTATUS);
3480 DUMPREG(DISPC_IRQENABLE);
3481 DUMPREG(DISPC_CONTROL);
3482 DUMPREG(DISPC_CONFIG);
3483 DUMPREG(DISPC_CAPABLE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003484 DUMPREG(DISPC_LINE_STATUS);
3485 DUMPREG(DISPC_LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +05303486 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
3487 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003488 DUMPREG(DISPC_GLOBAL_ALPHA);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003489 if (dss_has_feature(FEAT_MGR_LCD2)) {
3490 DUMPREG(DISPC_CONTROL2);
3491 DUMPREG(DISPC_CONFIG2);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003492 }
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303493 if (dss_has_feature(FEAT_MGR_LCD3)) {
3494 DUMPREG(DISPC_CONTROL3);
3495 DUMPREG(DISPC_CONFIG3);
3496 }
Tomi Valkeinen29fceee2013-11-14 11:38:25 +02003497 if (dss_has_feature(FEAT_MFLAG))
3498 DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003499
Archit Taneja5010be82011-08-05 19:06:00 +05303500#undef DUMPREG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003501
Archit Taneja5010be82011-08-05 19:06:00 +05303502#define DISPC_REG(i, name) name(i)
Archit Taneja4dd2da12011-08-05 19:06:01 +05303503#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
Tomi Valkeinen311d5ce2012-09-28 13:58:14 +03003504 (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303505 dispc_read_reg(DISPC_REG(i, r)))
3506
Archit Taneja4dd2da12011-08-05 19:06:01 +05303507 p_names = mgr_names;
Archit Taneja5010be82011-08-05 19:06:00 +05303508
Archit Taneja4dd2da12011-08-05 19:06:01 +05303509 /* DISPC channel specific registers */
3510 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
3511 DUMPREG(i, DISPC_DEFAULT_COLOR);
3512 DUMPREG(i, DISPC_TRANS_COLOR);
3513 DUMPREG(i, DISPC_SIZE_MGR);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003514
Archit Taneja4dd2da12011-08-05 19:06:01 +05303515 if (i == OMAP_DSS_CHANNEL_DIGIT)
3516 continue;
Archit Taneja5010be82011-08-05 19:06:00 +05303517
Archit Taneja4dd2da12011-08-05 19:06:01 +05303518 DUMPREG(i, DISPC_TIMING_H);
3519 DUMPREG(i, DISPC_TIMING_V);
3520 DUMPREG(i, DISPC_POL_FREQ);
3521 DUMPREG(i, DISPC_DIVISORo);
Archit Taneja5010be82011-08-05 19:06:00 +05303522
Archit Taneja4dd2da12011-08-05 19:06:01 +05303523 DUMPREG(i, DISPC_DATA_CYCLE1);
3524 DUMPREG(i, DISPC_DATA_CYCLE2);
3525 DUMPREG(i, DISPC_DATA_CYCLE3);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003526
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003527 if (dss_has_feature(FEAT_CPR)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303528 DUMPREG(i, DISPC_CPR_COEF_R);
3529 DUMPREG(i, DISPC_CPR_COEF_G);
3530 DUMPREG(i, DISPC_CPR_COEF_B);
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003531 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003532 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003533
Archit Taneja4dd2da12011-08-05 19:06:01 +05303534 p_names = ovl_names;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003535
Archit Taneja4dd2da12011-08-05 19:06:01 +05303536 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
3537 DUMPREG(i, DISPC_OVL_BA0);
3538 DUMPREG(i, DISPC_OVL_BA1);
3539 DUMPREG(i, DISPC_OVL_POSITION);
3540 DUMPREG(i, DISPC_OVL_SIZE);
3541 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3542 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3543 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3544 DUMPREG(i, DISPC_OVL_ROW_INC);
3545 DUMPREG(i, DISPC_OVL_PIXEL_INC);
Tomi Valkeinenaba837a2014-09-29 20:46:16 +00003546
Archit Taneja4dd2da12011-08-05 19:06:01 +05303547 if (dss_has_feature(FEAT_PRELOAD))
3548 DUMPREG(i, DISPC_OVL_PRELOAD);
Tomi Valkeinenaba837a2014-09-29 20:46:16 +00003549 if (dss_has_feature(FEAT_MFLAG))
3550 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003551
Archit Taneja4dd2da12011-08-05 19:06:01 +05303552 if (i == OMAP_DSS_GFX) {
3553 DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
3554 DUMPREG(i, DISPC_OVL_TABLE_BA);
3555 continue;
3556 }
3557
3558 DUMPREG(i, DISPC_OVL_FIR);
3559 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3560 DUMPREG(i, DISPC_OVL_ACCU0);
3561 DUMPREG(i, DISPC_OVL_ACCU1);
3562 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3563 DUMPREG(i, DISPC_OVL_BA0_UV);
3564 DUMPREG(i, DISPC_OVL_BA1_UV);
3565 DUMPREG(i, DISPC_OVL_FIR2);
3566 DUMPREG(i, DISPC_OVL_ACCU2_0);
3567 DUMPREG(i, DISPC_OVL_ACCU2_1);
3568 }
3569 if (dss_has_feature(FEAT_ATTR2))
3570 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
Archit Taneja5010be82011-08-05 19:06:00 +05303571 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003572
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02003573 if (dispc.feat->has_writeback) {
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003574 i = OMAP_DSS_WB;
3575 DUMPREG(i, DISPC_OVL_BA0);
3576 DUMPREG(i, DISPC_OVL_BA1);
3577 DUMPREG(i, DISPC_OVL_SIZE);
3578 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3579 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3580 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3581 DUMPREG(i, DISPC_OVL_ROW_INC);
3582 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3583
3584 if (dss_has_feature(FEAT_MFLAG))
3585 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
3586
3587 DUMPREG(i, DISPC_OVL_FIR);
3588 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3589 DUMPREG(i, DISPC_OVL_ACCU0);
3590 DUMPREG(i, DISPC_OVL_ACCU1);
3591 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3592 DUMPREG(i, DISPC_OVL_BA0_UV);
3593 DUMPREG(i, DISPC_OVL_BA1_UV);
3594 DUMPREG(i, DISPC_OVL_FIR2);
3595 DUMPREG(i, DISPC_OVL_ACCU2_0);
3596 DUMPREG(i, DISPC_OVL_ACCU2_1);
3597 }
3598 if (dss_has_feature(FEAT_ATTR2))
3599 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3600 }
3601
Archit Taneja5010be82011-08-05 19:06:00 +05303602#undef DISPC_REG
3603#undef DUMPREG
3604
3605#define DISPC_REG(plane, name, i) name(plane, i)
3606#define DUMPREG(plane, name, i) \
Archit Taneja4dd2da12011-08-05 19:06:01 +05303607 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
Tomi Valkeinen311d5ce2012-09-28 13:58:14 +03003608 (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303609 dispc_read_reg(DISPC_REG(plane, name, i)))
3610
Archit Taneja4dd2da12011-08-05 19:06:01 +05303611 /* Video pipeline coefficient registers */
Archit Taneja5010be82011-08-05 19:06:00 +05303612
Archit Taneja4dd2da12011-08-05 19:06:01 +05303613 /* start from OMAP_DSS_VIDEO1 */
3614 for (i = 1; i < dss_feat_get_num_ovls(); i++) {
3615 for (j = 0; j < 8; j++)
3616 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303617
Archit Taneja4dd2da12011-08-05 19:06:01 +05303618 for (j = 0; j < 8; j++)
3619 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303620
Archit Taneja4dd2da12011-08-05 19:06:01 +05303621 for (j = 0; j < 5; j++)
3622 DUMPREG(i, DISPC_OVL_CONV_COEF, j);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003623
Archit Taneja4dd2da12011-08-05 19:06:01 +05303624 if (dss_has_feature(FEAT_FIR_COEF_V)) {
3625 for (j = 0; j < 8; j++)
3626 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
3627 }
Amber Jainab5ca072011-05-19 19:47:53 +05303628
Archit Taneja4dd2da12011-08-05 19:06:01 +05303629 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3630 for (j = 0; j < 8; j++)
3631 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303632
Archit Taneja4dd2da12011-08-05 19:06:01 +05303633 for (j = 0; j < 8; j++)
3634 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303635
Archit Taneja4dd2da12011-08-05 19:06:01 +05303636 for (j = 0; j < 8; j++)
3637 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
3638 }
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003639 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003640
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003641 dispc_runtime_put();
Archit Taneja5010be82011-08-05 19:06:00 +05303642
3643#undef DISPC_REG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003644#undef DUMPREG
3645}
3646
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003647/* calculate clock rates using dividers in cinfo */
3648int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
3649 struct dispc_clock_info *cinfo)
3650{
3651 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3652 return -EINVAL;
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003653 if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003654 return -EINVAL;
3655
3656 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3657 cinfo->pck = cinfo->lck / cinfo->pck_div;
3658
3659 return 0;
3660}
3661
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003662bool dispc_div_calc(unsigned long dispc,
3663 unsigned long pck_min, unsigned long pck_max,
3664 dispc_div_calc_func func, void *data)
3665{
3666 int lckd, lckd_start, lckd_stop;
3667 int pckd, pckd_start, pckd_stop;
3668 unsigned long pck, lck;
3669 unsigned long lck_max;
3670 unsigned long pckd_hw_min, pckd_hw_max;
3671 unsigned min_fck_per_pck;
3672 unsigned long fck;
3673
3674#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
3675 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
3676#else
3677 min_fck_per_pck = 0;
3678#endif
3679
3680 pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
3681 pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
3682
3683 lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
3684
3685 pck_min = pck_min ? pck_min : 1;
3686 pck_max = pck_max ? pck_max : ULONG_MAX;
3687
3688 lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
3689 lckd_stop = min(dispc / pck_min, 255ul);
3690
3691 for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
3692 lck = dispc / lckd;
3693
3694 pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
3695 pckd_stop = min(lck / pck_min, pckd_hw_max);
3696
3697 for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
3698 pck = lck / pckd;
3699
3700 /*
3701 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
3702 * clock, which means we're configuring DISPC fclk here
3703 * also. Thus we need to use the calculated lck. For
3704 * OMAP4+ the DISPC fclk is a separate clock.
3705 */
3706 if (dss_has_feature(FEAT_CORE_CLK_DIV))
3707 fck = dispc_core_clk_rate();
3708 else
3709 fck = lck;
3710
3711 if (fck < pck * min_fck_per_pck)
3712 continue;
3713
3714 if (func(lckd, pckd, lck, pck, data))
3715 return true;
3716 }
3717 }
3718
3719 return false;
3720}
3721
Archit Tanejaf0d08f82012-06-29 14:00:54 +05303722void dispc_mgr_set_clock_div(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02003723 const struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003724{
3725 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3726 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3727
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003728 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003729}
3730
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003731int dispc_mgr_get_clock_div(enum omap_channel channel,
Sumit Semwalff1b2cde2010-12-02 11:27:11 +00003732 struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003733{
3734 unsigned long fck;
3735
3736 fck = dispc_fclk_rate();
3737
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003738 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3739 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003740
3741 cinfo->lck = fck / cinfo->lck_div;
3742 cinfo->pck = cinfo->lck / cinfo->pck_div;
3743
3744 return 0;
3745}
3746
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003747u32 dispc_read_irqstatus(void)
3748{
3749 return dispc_read_reg(DISPC_IRQSTATUS);
3750}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003751EXPORT_SYMBOL(dispc_read_irqstatus);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003752
3753void dispc_clear_irqstatus(u32 mask)
3754{
3755 dispc_write_reg(DISPC_IRQSTATUS, mask);
3756}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003757EXPORT_SYMBOL(dispc_clear_irqstatus);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003758
3759u32 dispc_read_irqenable(void)
3760{
3761 return dispc_read_reg(DISPC_IRQENABLE);
3762}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003763EXPORT_SYMBOL(dispc_read_irqenable);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003764
3765void dispc_write_irqenable(u32 mask)
3766{
3767 u32 old_mask = dispc_read_reg(DISPC_IRQENABLE);
3768
3769 /* clear the irqstatus for newly enabled irqs */
3770 dispc_clear_irqstatus((mask ^ old_mask) & mask);
3771
3772 dispc_write_reg(DISPC_IRQENABLE, mask);
3773}
Tomi Valkeinen348be692012-11-07 18:17:35 +02003774EXPORT_SYMBOL(dispc_write_irqenable);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003775
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003776void dispc_enable_sidle(void)
3777{
3778 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3779}
3780
3781void dispc_disable_sidle(void)
3782{
3783 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3784}
3785
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003786u32 dispc_mgr_gamma_size(enum omap_channel channel)
3787{
3788 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3789
3790 if (!dispc.feat->has_gamma_table)
3791 return 0;
3792
3793 return gdesc->len;
3794}
3795EXPORT_SYMBOL(dispc_mgr_gamma_size);
3796
3797static void dispc_mgr_write_gamma_table(enum omap_channel channel)
3798{
3799 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3800 u32 *table = dispc.gamma_table[channel];
3801 unsigned int i;
3802
3803 DSSDBG("%s: channel %d\n", __func__, channel);
3804
3805 for (i = 0; i < gdesc->len; ++i) {
3806 u32 v = table[i];
3807
3808 if (gdesc->has_index)
3809 v |= i << 24;
3810 else if (i == 0)
3811 v |= 1 << 31;
3812
3813 dispc_write_reg(gdesc->reg, v);
3814 }
3815}
3816
3817static void dispc_restore_gamma_tables(void)
3818{
3819 DSSDBG("%s()\n", __func__);
3820
3821 if (!dispc.feat->has_gamma_table)
3822 return;
3823
3824 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD);
3825
3826 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT);
3827
3828 if (dss_has_feature(FEAT_MGR_LCD2))
3829 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2);
3830
3831 if (dss_has_feature(FEAT_MGR_LCD3))
3832 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3);
3833}
3834
3835static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
3836 { .red = 0, .green = 0, .blue = 0, },
3837 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
3838};
3839
3840void dispc_mgr_set_gamma(enum omap_channel channel,
3841 const struct drm_color_lut *lut,
3842 unsigned int length)
3843{
3844 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3845 u32 *table = dispc.gamma_table[channel];
3846 uint i;
3847
3848 DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__,
3849 channel, length, gdesc->len);
3850
3851 if (!dispc.feat->has_gamma_table)
3852 return;
3853
3854 if (lut == NULL || length < 2) {
3855 lut = dispc_mgr_gamma_default_lut;
3856 length = ARRAY_SIZE(dispc_mgr_gamma_default_lut);
3857 }
3858
3859 for (i = 0; i < length - 1; ++i) {
3860 uint first = i * (gdesc->len - 1) / (length - 1);
3861 uint last = (i + 1) * (gdesc->len - 1) / (length - 1);
3862 uint w = last - first;
3863 u16 r, g, b;
3864 uint j;
3865
3866 if (w == 0)
3867 continue;
3868
3869 for (j = 0; j <= w; j++) {
3870 r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
3871 g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
3872 b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
3873
3874 r >>= 16 - gdesc->bits;
3875 g >>= 16 - gdesc->bits;
3876 b >>= 16 - gdesc->bits;
3877
3878 table[first + j] = (r << (gdesc->bits * 2)) |
3879 (g << gdesc->bits) | b;
3880 }
3881 }
3882
3883 if (dispc.is_enabled)
3884 dispc_mgr_write_gamma_table(channel);
3885}
3886EXPORT_SYMBOL(dispc_mgr_set_gamma);
3887
3888static int dispc_init_gamma_tables(void)
3889{
3890 int channel;
3891
3892 if (!dispc.feat->has_gamma_table)
3893 return 0;
3894
3895 for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) {
3896 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3897 u32 *gt;
3898
3899 if (channel == OMAP_DSS_CHANNEL_LCD2 &&
3900 !dss_has_feature(FEAT_MGR_LCD2))
3901 continue;
3902
3903 if (channel == OMAP_DSS_CHANNEL_LCD3 &&
3904 !dss_has_feature(FEAT_MGR_LCD3))
3905 continue;
3906
3907 gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len,
3908 sizeof(u32), GFP_KERNEL);
3909 if (!gt)
3910 return -ENOMEM;
3911
3912 dispc.gamma_table[channel] = gt;
3913
3914 dispc_mgr_set_gamma(channel, NULL, 0);
3915 }
3916 return 0;
3917}
3918
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003919static void _omap_dispc_initial_config(void)
3920{
3921 u32 l;
3922
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003923 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3924 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3925 l = dispc_read_reg(DISPC_DIVISOR);
3926 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3927 l = FLD_MOD(l, 1, 0, 0);
3928 l = FLD_MOD(l, 1, 23, 16);
3929 dispc_write_reg(DISPC_DIVISOR, l);
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003930
3931 dispc.core_clk_rate = dispc_fclk_rate();
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003932 }
3933
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003934 /* Use gamma table mode, instead of palette mode */
3935 if (dispc.feat->has_gamma_table)
3936 REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3);
3937
3938 /* For older DSS versions (FEAT_FUNCGATED) this enables
3939 * func-clock auto-gating. For newer versions
3940 * (dispc.feat->has_gamma_table) this enables tv-out gamma tables.
3941 */
3942 if (dss_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table)
Archit Taneja6ced40b2010-12-02 11:27:13 +00003943 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003944
Archit Taneja6e5264b2012-09-11 12:04:47 +05303945 dispc_setup_color_conv_coef();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003946
3947 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3948
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003949 dispc_init_fifos();
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03003950
3951 dispc_configure_burst_sizes();
Archit Taneja54128702011-09-08 11:29:17 +05303952
3953 dispc_ovl_enable_zorder_planes();
Archit Tanejad0df9a22013-03-26 19:15:25 +05303954
3955 if (dispc.feat->mstandby_workaround)
3956 REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00003957
3958 if (dss_has_feature(FEAT_MFLAG))
3959 dispc_init_mflag();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003960}
3961
Tomi Valkeinenede92692015-06-04 14:12:16 +03003962static const struct dispc_features omap24xx_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303963 .sw_start = 5,
3964 .fp_start = 15,
3965 .bp_start = 27,
3966 .sw_max = 64,
3967 .vp_max = 255,
3968 .hp_max = 256,
Archit Taneja33b89922012-11-14 13:50:15 +05303969 .mgr_width_start = 10,
3970 .mgr_height_start = 26,
3971 .mgr_width_max = 2048,
3972 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303973 .max_lcd_pclk = 66500000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303974 .calc_scaling = dispc_ovl_calc_scaling_24xx,
3975 .calc_core_clk = calc_core_clk_24xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003976 .num_fifos = 3,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02003977 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303978 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03003979 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303980};
3981
Tomi Valkeinenede92692015-06-04 14:12:16 +03003982static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303983 .sw_start = 5,
3984 .fp_start = 15,
3985 .bp_start = 27,
3986 .sw_max = 64,
3987 .vp_max = 255,
3988 .hp_max = 256,
Archit Taneja33b89922012-11-14 13:50:15 +05303989 .mgr_width_start = 10,
3990 .mgr_height_start = 26,
3991 .mgr_width_max = 2048,
3992 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303993 .max_lcd_pclk = 173000000,
3994 .max_tv_pclk = 59000000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303995 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3996 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003997 .num_fifos = 3,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02003998 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303999 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03004000 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304001};
4002
Tomi Valkeinenede92692015-06-04 14:12:16 +03004003static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304004 .sw_start = 7,
4005 .fp_start = 19,
4006 .bp_start = 31,
4007 .sw_max = 256,
4008 .vp_max = 4095,
4009 .hp_max = 4096,
Archit Taneja33b89922012-11-14 13:50:15 +05304010 .mgr_width_start = 10,
4011 .mgr_height_start = 26,
4012 .mgr_width_max = 2048,
4013 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304014 .max_lcd_pclk = 173000000,
4015 .max_tv_pclk = 59000000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304016 .calc_scaling = dispc_ovl_calc_scaling_34xx,
4017 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03004018 .num_fifos = 3,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02004019 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304020 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03004021 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304022};
4023
Tomi Valkeinenede92692015-06-04 14:12:16 +03004024static const struct dispc_features omap44xx_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304025 .sw_start = 7,
4026 .fp_start = 19,
4027 .bp_start = 31,
4028 .sw_max = 256,
4029 .vp_max = 4095,
4030 .hp_max = 4096,
Archit Taneja33b89922012-11-14 13:50:15 +05304031 .mgr_width_start = 10,
4032 .mgr_height_start = 26,
4033 .mgr_width_max = 2048,
4034 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304035 .max_lcd_pclk = 170000000,
4036 .max_tv_pclk = 185625000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304037 .calc_scaling = dispc_ovl_calc_scaling_44xx,
4038 .calc_core_clk = calc_core_clk_44xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03004039 .num_fifos = 5,
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +03004040 .gfx_fifo_workaround = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304041 .set_max_preload = true,
Tomi Valkeinene5f80912015-10-21 13:08:59 +03004042 .supports_sync_align = true,
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02004043 .has_writeback = true,
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02004044 .supports_double_pixel = true,
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02004045 .reverse_ilace_field_order = true,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004046 .has_gamma_table = true,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004047 .has_gamma_i734_bug = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304048};
4049
Tomi Valkeinenede92692015-06-04 14:12:16 +03004050static const struct dispc_features omap54xx_dispc_feats = {
Archit Taneja264236f2012-11-14 13:50:16 +05304051 .sw_start = 7,
4052 .fp_start = 19,
4053 .bp_start = 31,
4054 .sw_max = 256,
4055 .vp_max = 4095,
4056 .hp_max = 4096,
4057 .mgr_width_start = 11,
4058 .mgr_height_start = 27,
4059 .mgr_width_max = 4096,
4060 .mgr_height_max = 4096,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304061 .max_lcd_pclk = 170000000,
4062 .max_tv_pclk = 186000000,
Archit Taneja264236f2012-11-14 13:50:16 +05304063 .calc_scaling = dispc_ovl_calc_scaling_44xx,
4064 .calc_core_clk = calc_core_clk_44xx,
4065 .num_fifos = 5,
4066 .gfx_fifo_workaround = true,
Archit Tanejad0df9a22013-03-26 19:15:25 +05304067 .mstandby_workaround = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304068 .set_max_preload = true,
Tomi Valkeinene5f80912015-10-21 13:08:59 +03004069 .supports_sync_align = true,
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02004070 .has_writeback = true,
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02004071 .supports_double_pixel = true,
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02004072 .reverse_ilace_field_order = true,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004073 .has_gamma_table = true,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004074 .has_gamma_i734_bug = true,
Archit Taneja264236f2012-11-14 13:50:16 +05304075};
4076
Tomi Valkeinenede92692015-06-04 14:12:16 +03004077static int dispc_init_features(struct platform_device *pdev)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304078{
4079 const struct dispc_features *src;
4080 struct dispc_features *dst;
4081
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004082 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304083 if (!dst) {
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004084 dev_err(&pdev->dev, "Failed to allocate DISPC Features\n");
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304085 return -ENOMEM;
4086 }
4087
Tomi Valkeinenb2c7d542012-10-18 13:46:29 +03004088 switch (omapdss_get_version()) {
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004089 case OMAPDSS_VER_OMAP24xx:
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304090 src = &omap24xx_dispc_feats;
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004091 break;
4092
4093 case OMAPDSS_VER_OMAP34xx_ES1:
4094 src = &omap34xx_rev1_0_dispc_feats;
4095 break;
4096
4097 case OMAPDSS_VER_OMAP34xx_ES3:
4098 case OMAPDSS_VER_OMAP3630:
4099 case OMAPDSS_VER_AM35xx:
Sathya Prakash M Rd6279d42014-03-24 16:31:51 +05304100 case OMAPDSS_VER_AM43xx:
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004101 src = &omap34xx_rev3_0_dispc_feats;
4102 break;
4103
4104 case OMAPDSS_VER_OMAP4430_ES1:
4105 case OMAPDSS_VER_OMAP4430_ES2:
4106 case OMAPDSS_VER_OMAP4:
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304107 src = &omap44xx_dispc_feats;
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004108 break;
4109
4110 case OMAPDSS_VER_OMAP5:
Tomi Valkeinen93550922014-12-31 11:25:48 +02004111 case OMAPDSS_VER_DRA7xx:
Archit Taneja264236f2012-11-14 13:50:16 +05304112 src = &omap54xx_dispc_feats;
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004113 break;
4114
4115 default:
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304116 return -ENODEV;
4117 }
4118
4119 memcpy(dst, src, sizeof(*dst));
4120 dispc.feat = dst;
4121
4122 return 0;
4123}
4124
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004125static irqreturn_t dispc_irq_handler(int irq, void *arg)
4126{
4127 if (!dispc.is_enabled)
4128 return IRQ_NONE;
4129
4130 return dispc.user_handler(irq, dispc.user_data);
4131}
4132
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004133int dispc_request_irq(irq_handler_t handler, void *dev_id)
4134{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004135 int r;
4136
4137 if (dispc.user_handler != NULL)
4138 return -EBUSY;
4139
4140 dispc.user_handler = handler;
4141 dispc.user_data = dev_id;
4142
4143 /* ensure the dispc_irq_handler sees the values above */
4144 smp_wmb();
4145
4146 r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler,
4147 IRQF_SHARED, "OMAP DISPC", &dispc);
4148 if (r) {
4149 dispc.user_handler = NULL;
4150 dispc.user_data = NULL;
4151 }
4152
4153 return r;
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004154}
Tomi Valkeinen348be692012-11-07 18:17:35 +02004155EXPORT_SYMBOL(dispc_request_irq);
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004156
4157void dispc_free_irq(void *dev_id)
4158{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004159 devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc);
4160
4161 dispc.user_handler = NULL;
4162 dispc.user_data = NULL;
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004163}
Tomi Valkeinen348be692012-11-07 18:17:35 +02004164EXPORT_SYMBOL(dispc_free_irq);
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004165
Jyri Sarhafbff0102016-06-07 15:09:16 +03004166/*
4167 * Workaround for errata i734 in DSS dispc
4168 * - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
4169 *
4170 * For gamma tables to work on LCD1 the GFX plane has to be used at
4171 * least once after DSS HW has come out of reset. The workaround
4172 * sets up a minimal LCD setup with GFX plane and waits for one
4173 * vertical sync irq before disabling the setup and continuing with
4174 * the context restore. The physical outputs are gated during the
4175 * operation. This workaround requires that gamma table's LOADMODE
4176 * is set to 0x2 in DISPC_CONTROL1 register.
4177 *
4178 * For details see:
4179 * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata
4180 * Literature Number: SWPZ037E
4181 * Or some other relevant errata document for the DSS IP version.
4182 */
4183
4184static const struct dispc_errata_i734_data {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004185 struct videomode vm;
Jyri Sarhafbff0102016-06-07 15:09:16 +03004186 struct omap_overlay_info ovli;
4187 struct omap_overlay_manager_info mgri;
4188 struct dss_lcd_mgr_config lcd_conf;
4189} i734 = {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004190 .vm = {
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03004191 .hactive = 8, .vactive = 1,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004192 .pixelclock = 16000000,
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03004193 .hsync_len = 8, .hfront_porch = 4, .hback_porch = 4,
Peter Ujfalusi458540c2016-09-22 14:06:53 +03004194 .vsync_len = 1, .vfront_porch = 1, .vback_porch = 1,
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03004195
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +03004196 .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
Peter Ujfalusid34afb72016-09-22 14:07:01 +03004197 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
4198 DISPLAY_FLAGS_PIXDATA_POSEDGE,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004199 },
4200 .ovli = {
4201 .screen_width = 1,
4202 .width = 1, .height = 1,
4203 .color_mode = OMAP_DSS_COLOR_RGB24U,
4204 .rotation = OMAP_DSS_ROT_0,
4205 .rotation_type = OMAP_DSS_ROT_DMA,
4206 .mirror = 0,
4207 .pos_x = 0, .pos_y = 0,
4208 .out_width = 0, .out_height = 0,
4209 .global_alpha = 0xff,
4210 .pre_mult_alpha = 0,
4211 .zorder = 0,
4212 },
4213 .mgri = {
4214 .default_color = 0,
4215 .trans_enabled = false,
4216 .partial_alpha_enabled = false,
4217 .cpr_enable = false,
4218 },
4219 .lcd_conf = {
4220 .io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
4221 .stallmode = false,
4222 .fifohandcheck = false,
4223 .clock_info = {
4224 .lck_div = 1,
4225 .pck_div = 2,
4226 },
4227 .video_port_width = 24,
4228 .lcden_sig_polarity = 0,
4229 },
4230};
4231
4232static struct i734_buf {
4233 size_t size;
4234 dma_addr_t paddr;
4235 void *vaddr;
4236} i734_buf;
4237
4238static int dispc_errata_i734_wa_init(void)
4239{
4240 if (!dispc.feat->has_gamma_i734_bug)
4241 return 0;
4242
4243 i734_buf.size = i734.ovli.width * i734.ovli.height *
4244 color_mode_to_bpp(i734.ovli.color_mode) / 8;
4245
4246 i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size,
4247 &i734_buf.paddr, GFP_KERNEL);
4248 if (!i734_buf.vaddr) {
4249 dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed",
4250 __func__);
4251 return -ENOMEM;
4252 }
4253
4254 return 0;
4255}
4256
4257static void dispc_errata_i734_wa_fini(void)
4258{
4259 if (!dispc.feat->has_gamma_i734_bug)
4260 return;
4261
4262 dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr,
4263 i734_buf.paddr);
4264}
4265
4266static void dispc_errata_i734_wa(void)
4267{
4268 u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD);
4269 struct omap_overlay_info ovli;
4270 struct dss_lcd_mgr_config lcd_conf;
4271 u32 gatestate;
4272 unsigned int count;
4273
4274 if (!dispc.feat->has_gamma_i734_bug)
4275 return;
4276
4277 gatestate = REG_GET(DISPC_CONFIG, 8, 4);
4278
4279 ovli = i734.ovli;
4280 ovli.paddr = i734_buf.paddr;
4281 lcd_conf = i734.lcd_conf;
4282
4283 /* Gate all LCD1 outputs */
4284 REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4);
4285
4286 /* Setup and enable GFX plane */
4287 dispc_ovl_set_channel_out(OMAP_DSS_GFX, OMAP_DSS_CHANNEL_LCD);
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004288 dispc_ovl_setup(OMAP_DSS_GFX, &ovli, false, &i734.vm, false);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004289 dispc_ovl_enable(OMAP_DSS_GFX, true);
4290
4291 /* Set up and enable display manager for LCD1 */
4292 dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri);
4293 dispc_calc_clock_rates(dss_get_dispc_clk_rate(),
4294 &lcd_conf.clock_info);
4295 dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf);
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004296 dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.vm);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004297
4298 dispc_clear_irqstatus(framedone_irq);
4299
4300 /* Enable and shut the channel to produce just one frame */
4301 dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, true);
4302 dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, false);
4303
4304 /* Busy wait for framedone. We can't fiddle with irq handlers
4305 * in PM resume. Typically the loop runs less than 5 times and
4306 * waits less than a micro second.
4307 */
4308 count = 0;
4309 while (!(dispc_read_irqstatus() & framedone_irq)) {
4310 if (count++ > 10000) {
4311 dev_err(&dispc.pdev->dev, "%s: framedone timeout\n",
4312 __func__);
4313 break;
4314 }
4315 }
4316 dispc_ovl_enable(OMAP_DSS_GFX, false);
4317
4318 /* Clear all irq bits before continuing */
4319 dispc_clear_irqstatus(0xffffffff);
4320
4321 /* Restore the original state to LCD1 output gates */
4322 REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4);
4323}
4324
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004325/* DISPC HW IP initialisation */
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004326static int dispc_bind(struct device *dev, struct device *master, void *data)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004327{
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004328 struct platform_device *pdev = to_platform_device(dev);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004329 u32 rev;
archit tanejaaffe3602011-02-23 08:41:03 +00004330 int r = 0;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004331 struct resource *dispc_mem;
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00004332 struct device_node *np = pdev->dev.of_node;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004333
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004334 dispc.pdev = pdev;
4335
Tomi Valkeinend49cd152014-11-10 12:23:00 +02004336 spin_lock_init(&dispc.control_lock);
4337
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004338 r = dispc_init_features(dispc.pdev);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304339 if (r)
4340 return r;
4341
Jyri Sarhafbff0102016-06-07 15:09:16 +03004342 r = dispc_errata_i734_wa_init();
4343 if (r)
4344 return r;
4345
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004346 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
4347 if (!dispc_mem) {
4348 DSSERR("can't get IORESOURCE_MEM DISPC\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004349 return -EINVAL;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004350 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004351
Julia Lawall6e2a14d2012-01-24 14:00:45 +01004352 dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start,
4353 resource_size(dispc_mem));
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004354 if (!dispc.base) {
4355 DSSERR("can't ioremap DISPC\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004356 return -ENOMEM;
archit tanejaaffe3602011-02-23 08:41:03 +00004357 }
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004358
archit tanejaaffe3602011-02-23 08:41:03 +00004359 dispc.irq = platform_get_irq(dispc.pdev, 0);
4360 if (dispc.irq < 0) {
4361 DSSERR("platform_get_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004362 return -ENODEV;
archit tanejaaffe3602011-02-23 08:41:03 +00004363 }
4364
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00004365 if (np && of_property_read_bool(np, "syscon-pol")) {
4366 dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
4367 if (IS_ERR(dispc.syscon_pol)) {
4368 dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
4369 return PTR_ERR(dispc.syscon_pol);
4370 }
4371
4372 if (of_property_read_u32_index(np, "syscon-pol", 1,
4373 &dispc.syscon_pol_offset)) {
4374 dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
4375 return -EINVAL;
4376 }
4377 }
4378
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004379 r = dispc_init_gamma_tables();
4380 if (r)
4381 return r;
4382
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004383 pm_runtime_enable(&pdev->dev);
4384
4385 r = dispc_runtime_get();
4386 if (r)
4387 goto err_runtime_get;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004388
4389 _omap_dispc_initial_config();
4390
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004391 rev = dispc_read_reg(DISPC_REVISION);
Sumit Semwala06b62f2011-01-24 06:22:03 +00004392 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004393 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4394
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004395 dispc_runtime_put();
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004396
Tomi Valkeinene40402c2012-03-02 18:01:07 +02004397 dss_debugfs_create_file("dispc", dispc_dump_regs);
4398
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004399 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004400
4401err_runtime_get:
4402 pm_runtime_disable(&pdev->dev);
archit tanejaaffe3602011-02-23 08:41:03 +00004403 return r;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004404}
4405
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004406static void dispc_unbind(struct device *dev, struct device *master,
4407 void *data)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004408{
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004409 pm_runtime_disable(dev);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004410
4411 dispc_errata_i734_wa_fini();
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004412}
Tomi Valkeinen04b1fc02013-05-14 10:55:19 +03004413
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004414static const struct component_ops dispc_component_ops = {
4415 .bind = dispc_bind,
4416 .unbind = dispc_unbind,
4417};
4418
4419static int dispc_probe(struct platform_device *pdev)
4420{
4421 return component_add(&pdev->dev, &dispc_component_ops);
4422}
4423
4424static int dispc_remove(struct platform_device *pdev)
4425{
4426 component_del(&pdev->dev, &dispc_component_ops);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004427 return 0;
4428}
4429
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004430static int dispc_runtime_suspend(struct device *dev)
4431{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004432 dispc.is_enabled = false;
4433 /* ensure the dispc_irq_handler sees the is_enabled value */
4434 smp_wmb();
4435 /* wait for current handler to finish before turning the DISPC off */
4436 synchronize_irq(dispc.irq);
4437
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004438 dispc_save_context();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004439
4440 return 0;
4441}
4442
4443static int dispc_runtime_resume(struct device *dev)
4444{
Tomi Valkeinen9229b512014-02-14 09:37:09 +02004445 /*
4446 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
4447 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
4448 * _omap_dispc_initial_config(). We can thus use it to detect if
4449 * we have lost register context.
4450 */
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004451 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
4452 _omap_dispc_initial_config();
Tomi Valkeinen9229b512014-02-14 09:37:09 +02004453
Jyri Sarhafbff0102016-06-07 15:09:16 +03004454 dispc_errata_i734_wa();
4455
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004456 dispc_restore_context();
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004457
4458 dispc_restore_gamma_tables();
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004459 }
Tomi Valkeinenbe07dcd72013-11-21 16:01:40 +02004460
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004461 dispc.is_enabled = true;
4462 /* ensure the dispc_irq_handler sees the is_enabled value */
4463 smp_wmb();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004464
4465 return 0;
4466}
4467
4468static const struct dev_pm_ops dispc_pm_ops = {
4469 .runtime_suspend = dispc_runtime_suspend,
4470 .runtime_resume = dispc_runtime_resume,
4471};
4472
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004473static const struct of_device_id dispc_of_match[] = {
4474 { .compatible = "ti,omap2-dispc", },
4475 { .compatible = "ti,omap3-dispc", },
4476 { .compatible = "ti,omap4-dispc", },
Tomi Valkeinen2e7e6b62014-04-16 13:16:43 +03004477 { .compatible = "ti,omap5-dispc", },
Tomi Valkeinen93550922014-12-31 11:25:48 +02004478 { .compatible = "ti,dra7-dispc", },
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004479 {},
4480};
4481
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004482static struct platform_driver omap_dispchw_driver = {
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004483 .probe = dispc_probe,
4484 .remove = dispc_remove,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004485 .driver = {
4486 .name = "omapdss_dispc",
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004487 .pm = &dispc_pm_ops,
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004488 .of_match_table = dispc_of_match,
Tomi Valkeinen422ccbd2014-10-16 09:54:25 +03004489 .suppress_bind_attrs = true,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004490 },
4491};
4492
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02004493int __init dispc_init_platform_driver(void)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004494{
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004495 return platform_driver_register(&omap_dispchw_driver);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004496}
4497
Tomi Valkeinenede92692015-06-04 14:12:16 +03004498void dispc_uninit_platform_driver(void)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004499{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02004500 platform_driver_unregister(&omap_dispchw_driver);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004501}