blob: 7ccbcfc1d011c2c6e03d201840d7a739b638e7ba [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 Valkeinen3e1d65c2017-05-04 10:40:46 +030043#include <drm/drm_fourcc.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020044
Peter Ujfalusi32043da2016-05-27 14:40:49 +030045#include "omapdss.h"
Tomi Valkeinen80c39712009-11-12 11:41:42 +020046#include "dss.h"
Archit Tanejaa0acb552010-09-15 19:20:00 +053047#include "dss_features.h"
Archit Taneja9b372c22011-05-06 11:45:49 +053048#include "dispc.h"
Tomi Valkeinen80c39712009-11-12 11:41:42 +020049
50/* DISPC */
Sumit Semwal8613b002010-12-02 11:27:09 +000051#define DISPC_SZ_REGS SZ_4K
Tomi Valkeinen80c39712009-11-12 11:41:42 +020052
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +030053enum omap_burst_size {
54 BURST_SIZE_X2 = 0,
55 BURST_SIZE_X4 = 1,
56 BURST_SIZE_X8 = 2,
57};
58
Tomi Valkeinen80c39712009-11-12 11:41:42 +020059#define REG_GET(idx, start, end) \
60 FLD_GET(dispc_read_reg(idx), start, end)
61
62#define REG_FLD_MOD(idx, val, start, end) \
63 dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end))
64
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053065struct dispc_features {
66 u8 sw_start;
67 u8 fp_start;
68 u8 bp_start;
69 u16 sw_max;
70 u16 vp_max;
71 u16 hp_max;
Archit Taneja33b89922012-11-14 13:50:15 +053072 u8 mgr_width_start;
73 u8 mgr_height_start;
74 u16 mgr_width_max;
75 u16 mgr_height_max;
Archit Tanejaca5ca692013-03-26 19:15:22 +053076 unsigned long max_lcd_pclk;
77 unsigned long max_tv_pclk;
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +030078 int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +030079 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053080 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +030081 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053082 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +053083 u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
Tomi Valkeinen8702ee52012-10-19 15:36:11 +030084 unsigned long (*calc_core_clk) (unsigned long pclk,
Archit Taneja8ba85302012-09-26 17:00:37 +053085 u16 width, u16 height, u16 out_width, u16 out_height,
86 bool mem_to_mem);
Tomi Valkeinen42a69612012-08-22 16:56:57 +030087 u8 num_fifos;
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +030088
89 /* swap GFX & WB fifos */
90 bool gfx_fifo_workaround:1;
Tomi Valkeinencffa9472012-11-08 10:01:33 +020091
92 /* no DISPC_IRQ_FRAMEDONETV on this SoC */
93 bool no_framedone_tv:1;
Archit Tanejad0df9a22013-03-26 19:15:25 +053094
95 /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
96 bool mstandby_workaround:1;
Archit Taneja8bc65552013-12-17 16:40:21 +053097
98 bool set_max_preload:1;
Tomi Valkeinenf2aee312015-04-10 12:48:34 +030099
100 /* PIXEL_INC is not added to the last pixel of a line */
101 bool last_pixel_inc_missing:1;
Tomi Valkeinene5f80912015-10-21 13:08:59 +0300102
103 /* POL_FREQ has ALIGN bit */
104 bool supports_sync_align:1;
Tomi Valkeinen20efbc32015-11-04 17:10:44 +0200105
106 bool has_writeback:1;
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +0200107
108 bool supports_double_pixel:1;
Tomi Valkeinenb7536d62016-01-13 18:41:36 +0200109
110 /*
111 * Field order for VENC is different than HDMI. We should handle this in
112 * some intelligent manner, but as the SoCs have either HDMI or VENC,
113 * never both, we can just use this flag for now.
114 */
115 bool reverse_ilace_field_order:1;
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300116
117 bool has_gamma_table:1;
Jyri Sarhafbff0102016-06-07 15:09:16 +0300118
119 bool has_gamma_i734_bug:1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530120};
121
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300122#define DISPC_MAX_NR_FIFOS 5
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300123#define DISPC_MAX_CHANNEL_GAMMA 4
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300124
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200125static struct {
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +0000126 struct platform_device *pdev;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200127 void __iomem *base;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300128
archit tanejaaffe3602011-02-23 08:41:03 +0000129 int irq;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +0300130 irq_handler_t user_handler;
131 void *user_data;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200132
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +0200133 unsigned long core_clk_rate;
Tomi Valkeinen5391e872013-05-16 10:44:13 +0300134 unsigned long tv_pclk_rate;
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +0200135
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300136 u32 fifo_size[DISPC_MAX_NR_FIFOS];
137 /* maps which plane is using a fifo. fifo-id -> plane-id */
138 int fifo_assignment[DISPC_MAX_NR_FIFOS];
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200139
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300140 bool ctx_valid;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200141 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200142
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300143 u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA];
144
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530145 const struct dispc_features *feat;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +0300146
147 bool is_enabled;
Tomi Valkeinen0006fd62014-09-05 19:15:03 +0000148
149 struct regmap *syscon_pol;
150 u32 syscon_pol_offset;
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200151
152 /* DISPC_CONTROL & DISPC_CONFIG lock*/
153 spinlock_t control_lock;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200154} dispc;
155
Amber Jain0d66cbb2011-05-19 19:47:54 +0530156enum omap_color_component {
157 /* used for all color formats for OMAP3 and earlier
158 * and for RGB and Y color component on OMAP4
159 */
160 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
161 /* used for UV component for
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300162 * DRM_FORMAT_YUYV, DRM_FORMAT_UYVY, DRM_FORMAT_NV12
Amber Jain0d66cbb2011-05-19 19:47:54 +0530163 * color formats on OMAP4
164 */
165 DISPC_COLOR_COMPONENT_UV = 1 << 1,
166};
167
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530168enum mgr_reg_fields {
169 DISPC_MGR_FLD_ENABLE,
170 DISPC_MGR_FLD_STNTFT,
171 DISPC_MGR_FLD_GO,
172 DISPC_MGR_FLD_TFTDATALINES,
173 DISPC_MGR_FLD_STALLMODE,
174 DISPC_MGR_FLD_TCKENABLE,
175 DISPC_MGR_FLD_TCKSELECTION,
176 DISPC_MGR_FLD_CPR,
177 DISPC_MGR_FLD_FIFOHANDCHECK,
178 /* used to maintain a count of the above fields */
179 DISPC_MGR_FLD_NUM,
180};
181
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300182struct dispc_reg_field {
183 u16 reg;
184 u8 high;
185 u8 low;
186};
187
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300188struct dispc_gamma_desc {
189 u32 len;
190 u32 bits;
191 u16 reg;
192 bool has_index;
193};
194
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530195static const struct {
196 const char *name;
197 u32 vsync_irq;
198 u32 framedone_irq;
199 u32 sync_lost_irq;
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300200 struct dispc_gamma_desc gamma;
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300201 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530202} mgr_desc[] = {
203 [OMAP_DSS_CHANNEL_LCD] = {
204 .name = "LCD",
205 .vsync_irq = DISPC_IRQ_VSYNC,
206 .framedone_irq = DISPC_IRQ_FRAMEDONE,
207 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300208 .gamma = {
209 .len = 256,
210 .bits = 8,
211 .reg = DISPC_GAMMA_TABLE0,
212 .has_index = true,
213 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530214 .reg_desc = {
215 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
216 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
217 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
218 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
219 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
220 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
221 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
222 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
223 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
224 },
225 },
226 [OMAP_DSS_CHANNEL_DIGIT] = {
227 .name = "DIGIT",
228 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200229 .framedone_irq = DISPC_IRQ_FRAMEDONETV,
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530230 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300231 .gamma = {
232 .len = 1024,
233 .bits = 10,
234 .reg = DISPC_GAMMA_TABLE2,
235 .has_index = false,
236 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530237 .reg_desc = {
238 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
239 [DISPC_MGR_FLD_STNTFT] = { },
240 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
241 [DISPC_MGR_FLD_TFTDATALINES] = { },
242 [DISPC_MGR_FLD_STALLMODE] = { },
243 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
244 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
245 [DISPC_MGR_FLD_CPR] = { },
246 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
247 },
248 },
249 [OMAP_DSS_CHANNEL_LCD2] = {
250 .name = "LCD2",
251 .vsync_irq = DISPC_IRQ_VSYNC2,
252 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
253 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300254 .gamma = {
255 .len = 256,
256 .bits = 8,
257 .reg = DISPC_GAMMA_TABLE1,
258 .has_index = true,
259 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530260 .reg_desc = {
261 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
262 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
263 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
264 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
265 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
266 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
267 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
268 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
269 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
270 },
271 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530272 [OMAP_DSS_CHANNEL_LCD3] = {
273 .name = "LCD3",
274 .vsync_irq = DISPC_IRQ_VSYNC3,
275 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
276 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300277 .gamma = {
278 .len = 256,
279 .bits = 8,
280 .reg = DISPC_GAMMA_TABLE3,
281 .has_index = true,
282 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530283 .reg_desc = {
284 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
285 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
286 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
287 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
288 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
289 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
290 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
291 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
292 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
293 },
294 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530295};
296
Archit Taneja6e5264b2012-09-11 12:04:47 +0530297struct color_conv_coef {
298 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
299 int full_range;
300};
301
Tomi Valkeinen65904152015-11-04 17:10:57 +0200302static unsigned long dispc_fclk_rate(void);
303static unsigned long dispc_core_clk_rate(void);
304static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
305static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
306
Jyri Sarha864050c2017-03-24 16:47:52 +0200307static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane);
308static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200309
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200310static void dispc_clear_irqstatus(u32 mask);
311static bool dispc_mgr_is_enabled(enum omap_channel channel);
312static void dispc_clear_irqstatus(u32 mask);
313
Archit Taneja55978cc2011-05-06 11:45:51 +0530314static inline void dispc_write_reg(const u16 idx, u32 val)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200315{
Archit Taneja55978cc2011-05-06 11:45:51 +0530316 __raw_writel(val, dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200317}
318
Archit Taneja55978cc2011-05-06 11:45:51 +0530319static inline u32 dispc_read_reg(const u16 idx)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200320{
Archit Taneja55978cc2011-05-06 11:45:51 +0530321 return __raw_readl(dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200322}
323
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530324static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
325{
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300326 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530327 return REG_GET(rfld.reg, rfld.high, rfld.low);
328}
329
330static void mgr_fld_write(enum omap_channel channel,
331 enum mgr_reg_fields regfld, int val) {
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300332 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200333 const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG;
334 unsigned long flags;
335
336 if (need_lock)
337 spin_lock_irqsave(&dispc.control_lock, flags);
338
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530339 REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200340
341 if (need_lock)
342 spin_unlock_irqrestore(&dispc.control_lock, flags);
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530343}
344
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200345#define SR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530346 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200347#define RR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530348 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200349
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300350static void dispc_save_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200351{
Archit Tanejac6104b82011-08-05 19:06:02 +0530352 int i, j;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200353
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300354 DSSDBG("dispc_save_context\n");
355
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200356 SR(IRQENABLE);
357 SR(CONTROL);
358 SR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200359 SR(LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +0530360 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
361 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300362 SR(GLOBAL_ALPHA);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000363 if (dss_has_feature(FEAT_MGR_LCD2)) {
364 SR(CONTROL2);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000365 SR(CONFIG2);
366 }
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530367 if (dss_has_feature(FEAT_MGR_LCD3)) {
368 SR(CONTROL3);
369 SR(CONFIG3);
370 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200371
Archit Tanejac6104b82011-08-05 19:06:02 +0530372 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
373 SR(DEFAULT_COLOR(i));
374 SR(TRANS_COLOR(i));
375 SR(SIZE_MGR(i));
376 if (i == OMAP_DSS_CHANNEL_DIGIT)
377 continue;
378 SR(TIMING_H(i));
379 SR(TIMING_V(i));
380 SR(POL_FREQ(i));
381 SR(DIVISORo(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200382
Archit Tanejac6104b82011-08-05 19:06:02 +0530383 SR(DATA_CYCLE1(i));
384 SR(DATA_CYCLE2(i));
385 SR(DATA_CYCLE3(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200386
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300387 if (dss_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530388 SR(CPR_COEF_R(i));
389 SR(CPR_COEF_G(i));
390 SR(CPR_COEF_B(i));
391 }
392 }
393
394 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
395 SR(OVL_BA0(i));
396 SR(OVL_BA1(i));
397 SR(OVL_POSITION(i));
398 SR(OVL_SIZE(i));
399 SR(OVL_ATTRIBUTES(i));
400 SR(OVL_FIFO_THRESHOLD(i));
401 SR(OVL_ROW_INC(i));
402 SR(OVL_PIXEL_INC(i));
403 if (dss_has_feature(FEAT_PRELOAD))
404 SR(OVL_PRELOAD(i));
405 if (i == OMAP_DSS_GFX) {
406 SR(OVL_WINDOW_SKIP(i));
407 SR(OVL_TABLE_BA(i));
408 continue;
409 }
410 SR(OVL_FIR(i));
411 SR(OVL_PICTURE_SIZE(i));
412 SR(OVL_ACCU0(i));
413 SR(OVL_ACCU1(i));
414
415 for (j = 0; j < 8; j++)
416 SR(OVL_FIR_COEF_H(i, j));
417
418 for (j = 0; j < 8; j++)
419 SR(OVL_FIR_COEF_HV(i, j));
420
421 for (j = 0; j < 5; j++)
422 SR(OVL_CONV_COEF(i, j));
423
424 if (dss_has_feature(FEAT_FIR_COEF_V)) {
425 for (j = 0; j < 8; j++)
426 SR(OVL_FIR_COEF_V(i, j));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300427 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000428
Archit Tanejac6104b82011-08-05 19:06:02 +0530429 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
430 SR(OVL_BA0_UV(i));
431 SR(OVL_BA1_UV(i));
432 SR(OVL_FIR2(i));
433 SR(OVL_ACCU2_0(i));
434 SR(OVL_ACCU2_1(i));
435
436 for (j = 0; j < 8; j++)
437 SR(OVL_FIR_COEF_H2(i, j));
438
439 for (j = 0; j < 8; j++)
440 SR(OVL_FIR_COEF_HV2(i, j));
441
442 for (j = 0; j < 8; j++)
443 SR(OVL_FIR_COEF_V2(i, j));
444 }
445 if (dss_has_feature(FEAT_ATTR2))
446 SR(OVL_ATTRIBUTES2(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000447 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200448
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600449 if (dss_has_feature(FEAT_CORE_CLK_DIV))
450 SR(DIVISOR);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300451
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300452 dispc.ctx_valid = true;
453
Tomi Valkeinen9229b512014-02-14 09:37:09 +0200454 DSSDBG("context saved\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200455}
456
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300457static void dispc_restore_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200458{
Tomi Valkeinen9229b512014-02-14 09:37:09 +0200459 int i, j;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300460
461 DSSDBG("dispc_restore_context\n");
462
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300463 if (!dispc.ctx_valid)
464 return;
465
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200466 /*RR(IRQENABLE);*/
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200467 /*RR(CONTROL);*/
468 RR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200469 RR(LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +0530470 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
471 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300472 RR(GLOBAL_ALPHA);
Archit Tanejac6104b82011-08-05 19:06:02 +0530473 if (dss_has_feature(FEAT_MGR_LCD2))
Sumit Semwal2a205f32010-12-02 11:27:12 +0000474 RR(CONFIG2);
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530475 if (dss_has_feature(FEAT_MGR_LCD3))
476 RR(CONFIG3);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200477
Archit Tanejac6104b82011-08-05 19:06:02 +0530478 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
479 RR(DEFAULT_COLOR(i));
480 RR(TRANS_COLOR(i));
481 RR(SIZE_MGR(i));
482 if (i == OMAP_DSS_CHANNEL_DIGIT)
483 continue;
484 RR(TIMING_H(i));
485 RR(TIMING_V(i));
486 RR(POL_FREQ(i));
487 RR(DIVISORo(i));
Archit Taneja9b372c22011-05-06 11:45:49 +0530488
Archit Tanejac6104b82011-08-05 19:06:02 +0530489 RR(DATA_CYCLE1(i));
490 RR(DATA_CYCLE2(i));
491 RR(DATA_CYCLE3(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000492
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300493 if (dss_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530494 RR(CPR_COEF_R(i));
495 RR(CPR_COEF_G(i));
496 RR(CPR_COEF_B(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300497 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000498 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200499
Archit Tanejac6104b82011-08-05 19:06:02 +0530500 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
501 RR(OVL_BA0(i));
502 RR(OVL_BA1(i));
503 RR(OVL_POSITION(i));
504 RR(OVL_SIZE(i));
505 RR(OVL_ATTRIBUTES(i));
506 RR(OVL_FIFO_THRESHOLD(i));
507 RR(OVL_ROW_INC(i));
508 RR(OVL_PIXEL_INC(i));
509 if (dss_has_feature(FEAT_PRELOAD))
510 RR(OVL_PRELOAD(i));
511 if (i == OMAP_DSS_GFX) {
512 RR(OVL_WINDOW_SKIP(i));
513 RR(OVL_TABLE_BA(i));
514 continue;
515 }
516 RR(OVL_FIR(i));
517 RR(OVL_PICTURE_SIZE(i));
518 RR(OVL_ACCU0(i));
519 RR(OVL_ACCU1(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200520
Archit Tanejac6104b82011-08-05 19:06:02 +0530521 for (j = 0; j < 8; j++)
522 RR(OVL_FIR_COEF_H(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200523
Archit Tanejac6104b82011-08-05 19:06:02 +0530524 for (j = 0; j < 8; j++)
525 RR(OVL_FIR_COEF_HV(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200526
Archit Tanejac6104b82011-08-05 19:06:02 +0530527 for (j = 0; j < 5; j++)
528 RR(OVL_CONV_COEF(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200529
Archit Tanejac6104b82011-08-05 19:06:02 +0530530 if (dss_has_feature(FEAT_FIR_COEF_V)) {
531 for (j = 0; j < 8; j++)
532 RR(OVL_FIR_COEF_V(i, j));
533 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200534
Archit Tanejac6104b82011-08-05 19:06:02 +0530535 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
536 RR(OVL_BA0_UV(i));
537 RR(OVL_BA1_UV(i));
538 RR(OVL_FIR2(i));
539 RR(OVL_ACCU2_0(i));
540 RR(OVL_ACCU2_1(i));
541
542 for (j = 0; j < 8; j++)
543 RR(OVL_FIR_COEF_H2(i, j));
544
545 for (j = 0; j < 8; j++)
546 RR(OVL_FIR_COEF_HV2(i, j));
547
548 for (j = 0; j < 8; j++)
549 RR(OVL_FIR_COEF_V2(i, j));
550 }
551 if (dss_has_feature(FEAT_ATTR2))
552 RR(OVL_ATTRIBUTES2(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300553 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200554
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600555 if (dss_has_feature(FEAT_CORE_CLK_DIV))
556 RR(DIVISOR);
557
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200558 /* enable last, because LCD & DIGIT enable are here */
559 RR(CONTROL);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000560 if (dss_has_feature(FEAT_MGR_LCD2))
561 RR(CONTROL2);
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530562 if (dss_has_feature(FEAT_MGR_LCD3))
563 RR(CONTROL3);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200564 /* clear spurious SYNC_LOST_DIGIT interrupts */
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +0300565 dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200566
567 /*
568 * enable last so IRQs won't trigger before
569 * the context is fully restored
570 */
571 RR(IRQENABLE);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300572
573 DSSDBG("context restored\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200574}
575
576#undef SR
577#undef RR
578
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300579int dispc_runtime_get(void)
580{
581 int r;
582
583 DSSDBG("dispc_runtime_get\n");
584
585 r = pm_runtime_get_sync(&dispc.pdev->dev);
586 WARN_ON(r < 0);
587 return r < 0 ? r : 0;
588}
589
590void dispc_runtime_put(void)
591{
592 int r;
593
594 DSSDBG("dispc_runtime_put\n");
595
Tomi Valkeinen0eaf9f52012-01-23 13:23:08 +0200596 r = pm_runtime_put_sync(&dispc.pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300597 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300598}
599
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200600static u32 dispc_mgr_get_vsync_irq(enum omap_channel channel)
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200601{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530602 return mgr_desc[channel].vsync_irq;
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200603}
604
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200605static u32 dispc_mgr_get_framedone_irq(enum omap_channel channel)
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200606{
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200607 if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv)
608 return 0;
609
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530610 return mgr_desc[channel].framedone_irq;
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200611}
612
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200613static u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel)
Tomi Valkeinencb699202012-10-17 10:38:52 +0300614{
615 return mgr_desc[channel].sync_lost_irq;
616}
617
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530618u32 dispc_wb_get_framedone_irq(void)
619{
620 return DISPC_IRQ_FRAMEDONEWB;
621}
622
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200623static void dispc_mgr_enable(enum omap_channel channel, bool enable)
Laurent Pinchart03af8152016-04-18 03:09:48 +0300624{
625 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
626 /* flush posted write */
627 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
628}
Laurent Pinchart03af8152016-04-18 03:09:48 +0300629
630static bool dispc_mgr_is_enabled(enum omap_channel channel)
631{
632 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
633}
634
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200635static bool dispc_mgr_go_busy(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200636{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530637 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200638}
639
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200640static void dispc_mgr_go(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200641{
Luis de Bethencourt0bcfdba2015-10-15 13:29:38 +0100642 WARN_ON(!dispc_mgr_is_enabled(channel));
Tomi Valkeinen3c91ee82012-10-19 15:06:07 +0300643 WARN_ON(dispc_mgr_go_busy(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200644
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530645 DSSDBG("GO %s\n", mgr_desc[channel].name);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200646
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530647 mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200648}
649
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530650bool dispc_wb_go_busy(void)
651{
652 return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
653}
654
655void dispc_wb_go(void)
656{
Jyri Sarha864050c2017-03-24 16:47:52 +0200657 enum omap_plane_id plane = OMAP_DSS_WB;
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530658 bool enable, go;
659
660 enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
661
662 if (!enable)
663 return;
664
665 go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
666 if (go) {
667 DSSERR("GO bit not down for WB\n");
668 return;
669 }
670
671 REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
672}
673
Jyri Sarha864050c2017-03-24 16:47:52 +0200674static void dispc_ovl_write_firh_reg(enum omap_plane_id plane, int reg,
675 u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200676{
Archit Taneja9b372c22011-05-06 11:45:49 +0530677 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200678}
679
Jyri Sarha864050c2017-03-24 16:47:52 +0200680static void dispc_ovl_write_firhv_reg(enum omap_plane_id plane, int reg,
681 u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200682{
Archit Taneja9b372c22011-05-06 11:45:49 +0530683 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200684}
685
Jyri Sarha864050c2017-03-24 16:47:52 +0200686static void dispc_ovl_write_firv_reg(enum omap_plane_id plane, int reg,
687 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
Jyri Sarha864050c2017-03-24 16:47:52 +0200692static void dispc_ovl_write_firh2_reg(enum omap_plane_id plane, int reg,
693 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530694{
695 BUG_ON(plane == OMAP_DSS_GFX);
696
697 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
698}
699
Jyri Sarha864050c2017-03-24 16:47:52 +0200700static void dispc_ovl_write_firhv2_reg(enum omap_plane_id plane, int reg,
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300701 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530702{
703 BUG_ON(plane == OMAP_DSS_GFX);
704
705 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
706}
707
Jyri Sarha864050c2017-03-24 16:47:52 +0200708static void dispc_ovl_write_firv2_reg(enum omap_plane_id plane, int reg,
709 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530710{
711 BUG_ON(plane == OMAP_DSS_GFX);
712
713 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
714}
715
Jyri Sarha864050c2017-03-24 16:47:52 +0200716static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc,
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530717 int fir_vinc, int five_taps,
718 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200719{
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530720 const struct dispc_coef *h_coef, *v_coef;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200721 int i;
722
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530723 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
724 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200725
726 for (i = 0; i < 8; i++) {
727 u32 h, hv;
728
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530729 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
730 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
731 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
732 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
733 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
734 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
735 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
736 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200737
Amber Jain0d66cbb2011-05-19 19:47:54 +0530738 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300739 dispc_ovl_write_firh_reg(plane, i, h);
740 dispc_ovl_write_firhv_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530741 } else {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300742 dispc_ovl_write_firh2_reg(plane, i, h);
743 dispc_ovl_write_firhv2_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530744 }
745
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200746 }
747
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200748 if (five_taps) {
749 for (i = 0; i < 8; i++) {
750 u32 v;
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530751 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
752 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530753 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300754 dispc_ovl_write_firv_reg(plane, i, v);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530755 else
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300756 dispc_ovl_write_firv2_reg(plane, i, v);
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200757 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200758 }
759}
760
Archit Taneja6e5264b2012-09-11 12:04:47 +0530761
Jyri Sarha864050c2017-03-24 16:47:52 +0200762static void dispc_ovl_write_color_conv_coef(enum omap_plane_id plane,
Archit Taneja6e5264b2012-09-11 12:04:47 +0530763 const struct color_conv_coef *ct)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200764{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200765#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
766
Archit Taneja6e5264b2012-09-11 12:04:47 +0530767 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
768 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
769 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
770 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
771 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200772
Archit Taneja6e5264b2012-09-11 12:04:47 +0530773 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200774
775#undef CVAL
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200776}
777
Archit Taneja6e5264b2012-09-11 12:04:47 +0530778static void dispc_setup_color_conv_coef(void)
779{
780 int i;
781 int num_ovl = dss_feat_get_num_ovls();
Archit Taneja6e5264b2012-09-11 12:04:47 +0530782 const struct color_conv_coef ctbl_bt601_5_ovl = {
Tomi Valkeinen7d18bbe2015-11-04 17:10:52 +0200783 /* YUV -> RGB */
Archit Taneja6e5264b2012-09-11 12:04:47 +0530784 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
785 };
786 const struct color_conv_coef ctbl_bt601_5_wb = {
Tomi Valkeinen7d18bbe2015-11-04 17:10:52 +0200787 /* RGB -> YUV */
788 66, 129, 25, 112, -94, -18, -38, -74, 112, 0,
Archit Taneja6e5264b2012-09-11 12:04:47 +0530789 };
790
791 for (i = 1; i < num_ovl; i++)
792 dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
793
Tomi Valkeinen20efbc32015-11-04 17:10:44 +0200794 if (dispc.feat->has_writeback)
795 dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb);
Archit Taneja6e5264b2012-09-11 12:04:47 +0530796}
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200797
Jyri Sarha864050c2017-03-24 16:47:52 +0200798static void dispc_ovl_set_ba0(enum omap_plane_id plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200799{
Archit Taneja9b372c22011-05-06 11:45:49 +0530800 dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200801}
802
Jyri Sarha864050c2017-03-24 16:47:52 +0200803static void dispc_ovl_set_ba1(enum omap_plane_id plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200804{
Archit Taneja9b372c22011-05-06 11:45:49 +0530805 dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200806}
807
Jyri Sarha864050c2017-03-24 16:47:52 +0200808static void dispc_ovl_set_ba0_uv(enum omap_plane_id plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530809{
810 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
811}
812
Jyri Sarha864050c2017-03-24 16:47:52 +0200813static void dispc_ovl_set_ba1_uv(enum omap_plane_id plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530814{
815 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
816}
817
Jyri Sarha864050c2017-03-24 16:47:52 +0200818static void dispc_ovl_set_pos(enum omap_plane_id plane,
Archit Tanejad79db852012-09-22 12:30:17 +0530819 enum omap_overlay_caps caps, int x, int y)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200820{
Archit Tanejad79db852012-09-22 12:30:17 +0530821 u32 val;
822
823 if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
824 return;
825
826 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530827
828 dispc_write_reg(DISPC_OVL_POSITION(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200829}
830
Jyri Sarha864050c2017-03-24 16:47:52 +0200831static void dispc_ovl_set_input_size(enum omap_plane_id plane, int width,
Archit Taneja78b687f2012-09-21 14:51:49 +0530832 int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200833{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200834 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530835
Archit Taneja36d87d92012-07-28 22:59:03 +0530836 if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
Archit Taneja9b372c22011-05-06 11:45:49 +0530837 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
838 else
839 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200840}
841
Jyri Sarha864050c2017-03-24 16:47:52 +0200842static void dispc_ovl_set_output_size(enum omap_plane_id plane, int width,
Archit Taneja78b687f2012-09-21 14:51:49 +0530843 int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200844{
845 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200846
847 BUG_ON(plane == OMAP_DSS_GFX);
848
849 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530850
Archit Taneja36d87d92012-07-28 22:59:03 +0530851 if (plane == OMAP_DSS_WB)
852 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
853 else
854 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200855}
856
Jyri Sarha864050c2017-03-24 16:47:52 +0200857static void dispc_ovl_set_zorder(enum omap_plane_id plane,
Archit Taneja5b54ed32012-09-26 16:55:27 +0530858 enum omap_overlay_caps caps, u8 zorder)
Archit Taneja54128702011-09-08 11:29:17 +0530859{
Archit Taneja5b54ed32012-09-26 16:55:27 +0530860 if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
Archit Taneja54128702011-09-08 11:29:17 +0530861 return;
862
863 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
864}
865
866static void dispc_ovl_enable_zorder_planes(void)
867{
868 int i;
869
870 if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
871 return;
872
873 for (i = 0; i < dss_feat_get_num_ovls(); i++)
874 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
875}
876
Jyri Sarha864050c2017-03-24 16:47:52 +0200877static void dispc_ovl_set_pre_mult_alpha(enum omap_plane_id plane,
Archit Taneja5b54ed32012-09-26 16:55:27 +0530878 enum omap_overlay_caps caps, bool enable)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100879{
Archit Taneja5b54ed32012-09-26 16:55:27 +0530880 if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100881 return;
882
Archit Taneja9b372c22011-05-06 11:45:49 +0530883 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
Rajkumar Nfd28a392010-11-04 12:28:42 +0100884}
885
Jyri Sarha864050c2017-03-24 16:47:52 +0200886static void dispc_ovl_setup_global_alpha(enum omap_plane_id plane,
Archit Taneja5b54ed32012-09-26 16:55:27 +0530887 enum omap_overlay_caps caps, u8 global_alpha)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200888{
Archit Tanejab8c095b2011-09-13 18:20:33 +0530889 static const unsigned shifts[] = { 0, 8, 16, 24, };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300890 int shift;
891
Archit Taneja5b54ed32012-09-26 16:55:27 +0530892 if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100893 return;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530894
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300895 shift = shifts[plane];
896 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200897}
898
Jyri Sarha864050c2017-03-24 16:47:52 +0200899static void dispc_ovl_set_pix_inc(enum omap_plane_id plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200900{
Archit Taneja9b372c22011-05-06 11:45:49 +0530901 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200902}
903
Jyri Sarha864050c2017-03-24 16:47:52 +0200904static void dispc_ovl_set_row_inc(enum omap_plane_id plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200905{
Archit Taneja9b372c22011-05-06 11:45:49 +0530906 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200907}
908
Tomi Valkeinen41aff422017-05-04 11:31:56 +0300909static void dispc_ovl_set_color_mode(enum omap_plane_id plane, u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200910{
911 u32 m = 0;
Amber Jainf20e4222011-05-19 19:47:50 +0530912 if (plane != OMAP_DSS_GFX) {
Tomi Valkeinen41aff422017-05-04 11:31:56 +0300913 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300914 case DRM_FORMAT_NV12:
Amber Jainf20e4222011-05-19 19:47:50 +0530915 m = 0x0; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300916 case DRM_FORMAT_XRGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530917 m = 0x1; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300918 case DRM_FORMAT_RGBA4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530919 m = 0x2; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300920 case DRM_FORMAT_RGBX4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530921 m = 0x4; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300922 case DRM_FORMAT_ARGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530923 m = 0x5; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300924 case DRM_FORMAT_RGB565:
Amber Jainf20e4222011-05-19 19:47:50 +0530925 m = 0x6; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300926 case DRM_FORMAT_ARGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +0530927 m = 0x7; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300928 case DRM_FORMAT_XRGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530929 m = 0x8; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300930 case DRM_FORMAT_RGB888:
Amber Jainf20e4222011-05-19 19:47:50 +0530931 m = 0x9; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300932 case DRM_FORMAT_YUYV:
Amber Jainf20e4222011-05-19 19:47:50 +0530933 m = 0xa; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300934 case DRM_FORMAT_UYVY:
Amber Jainf20e4222011-05-19 19:47:50 +0530935 m = 0xb; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300936 case DRM_FORMAT_ARGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530937 m = 0xc; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300938 case DRM_FORMAT_RGBA8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530939 m = 0xd; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300940 case DRM_FORMAT_RGBX8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530941 m = 0xe; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300942 case DRM_FORMAT_XRGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +0530943 m = 0xf; break;
944 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300945 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +0530946 }
947 } else {
Tomi Valkeinen41aff422017-05-04 11:31:56 +0300948 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300949 case DRM_FORMAT_RGBX4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530950 m = 0x4; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300951 case DRM_FORMAT_ARGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530952 m = 0x5; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300953 case DRM_FORMAT_RGB565:
Amber Jainf20e4222011-05-19 19:47:50 +0530954 m = 0x6; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300955 case DRM_FORMAT_ARGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +0530956 m = 0x7; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300957 case DRM_FORMAT_XRGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530958 m = 0x8; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300959 case DRM_FORMAT_RGB888:
Amber Jainf20e4222011-05-19 19:47:50 +0530960 m = 0x9; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300961 case DRM_FORMAT_XRGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530962 m = 0xa; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300963 case DRM_FORMAT_RGBA4444:
Amber Jainf20e4222011-05-19 19:47:50 +0530964 m = 0xb; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300965 case DRM_FORMAT_ARGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530966 m = 0xc; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300967 case DRM_FORMAT_RGBA8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530968 m = 0xd; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300969 case DRM_FORMAT_RGBX8888:
Amber Jainf20e4222011-05-19 19:47:50 +0530970 m = 0xe; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300971 case DRM_FORMAT_XRGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +0530972 m = 0xf; break;
973 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +0300974 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +0530975 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200976 }
977
Archit Taneja9b372c22011-05-06 11:45:49 +0530978 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200979}
980
Tomi Valkeinen41aff422017-05-04 11:31:56 +0300981static bool format_is_yuv(u32 fourcc)
Tomi Valkeinen5edec142017-05-04 09:13:32 +0300982{
Tomi Valkeinen41aff422017-05-04 11:31:56 +0300983 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300984 case DRM_FORMAT_YUYV:
985 case DRM_FORMAT_UYVY:
986 case DRM_FORMAT_NV12:
Tomi Valkeinen5edec142017-05-04 09:13:32 +0300987 return true;
988 default:
989 return false;
990 }
991}
992
Jyri Sarha864050c2017-03-24 16:47:52 +0200993static void dispc_ovl_configure_burst_type(enum omap_plane_id plane,
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +0530994 enum omap_dss_rotation_type rotation_type)
995{
996 if (dss_has_feature(FEAT_BURST_2D) == 0)
997 return;
998
999 if (rotation_type == OMAP_DSS_ROT_TILER)
1000 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
1001 else
1002 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
1003}
1004
Jyri Sarha864050c2017-03-24 16:47:52 +02001005static void dispc_ovl_set_channel_out(enum omap_plane_id plane,
1006 enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001007{
1008 int shift;
1009 u32 val;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001010 int chan = 0, chan2 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001011
1012 switch (plane) {
1013 case OMAP_DSS_GFX:
1014 shift = 8;
1015 break;
1016 case OMAP_DSS_VIDEO1:
1017 case OMAP_DSS_VIDEO2:
Archit Tanejab8c095b2011-09-13 18:20:33 +05301018 case OMAP_DSS_VIDEO3:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001019 shift = 16;
1020 break;
1021 default:
1022 BUG();
1023 return;
1024 }
1025
Archit Taneja9b372c22011-05-06 11:45:49 +05301026 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Sumit Semwal2a205f32010-12-02 11:27:12 +00001027 if (dss_has_feature(FEAT_MGR_LCD2)) {
1028 switch (channel) {
1029 case OMAP_DSS_CHANNEL_LCD:
1030 chan = 0;
1031 chan2 = 0;
1032 break;
1033 case OMAP_DSS_CHANNEL_DIGIT:
1034 chan = 1;
1035 chan2 = 0;
1036 break;
1037 case OMAP_DSS_CHANNEL_LCD2:
1038 chan = 0;
1039 chan2 = 1;
1040 break;
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +05301041 case OMAP_DSS_CHANNEL_LCD3:
1042 if (dss_has_feature(FEAT_MGR_LCD3)) {
1043 chan = 0;
1044 chan2 = 2;
1045 } else {
1046 BUG();
1047 return;
1048 }
1049 break;
Tomi Valkeinenc2665c42015-11-04 17:10:47 +02001050 case OMAP_DSS_CHANNEL_WB:
1051 chan = 0;
1052 chan2 = 3;
1053 break;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001054 default:
1055 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001056 return;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001057 }
1058
1059 val = FLD_MOD(val, chan, shift, shift);
1060 val = FLD_MOD(val, chan2, 31, 30);
1061 } else {
1062 val = FLD_MOD(val, channel, shift, shift);
1063 }
Archit Taneja9b372c22011-05-06 11:45:49 +05301064 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001065}
1066
Jyri Sarha864050c2017-03-24 16:47:52 +02001067static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane)
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001068{
1069 int shift;
1070 u32 val;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001071
1072 switch (plane) {
1073 case OMAP_DSS_GFX:
1074 shift = 8;
1075 break;
1076 case OMAP_DSS_VIDEO1:
1077 case OMAP_DSS_VIDEO2:
1078 case OMAP_DSS_VIDEO3:
1079 shift = 16;
1080 break;
1081 default:
1082 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001083 return 0;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001084 }
1085
1086 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1087
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001088 if (FLD_GET(val, shift, shift) == 1)
1089 return OMAP_DSS_CHANNEL_DIGIT;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001090
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001091 if (!dss_has_feature(FEAT_MGR_LCD2))
1092 return OMAP_DSS_CHANNEL_LCD;
1093
1094 switch (FLD_GET(val, 31, 30)) {
1095 case 0:
1096 default:
1097 return OMAP_DSS_CHANNEL_LCD;
1098 case 1:
1099 return OMAP_DSS_CHANNEL_LCD2;
1100 case 2:
1101 return OMAP_DSS_CHANNEL_LCD3;
Tomi Valkeinenc2665c42015-11-04 17:10:47 +02001102 case 3:
1103 return OMAP_DSS_CHANNEL_WB;
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001104 }
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001105}
1106
Archit Tanejad9ac7732012-09-22 12:38:19 +05301107void dispc_wb_set_channel_in(enum dss_writeback_channel channel)
1108{
Jyri Sarha864050c2017-03-24 16:47:52 +02001109 enum omap_plane_id plane = OMAP_DSS_WB;
Archit Tanejad9ac7732012-09-22 12:38:19 +05301110
1111 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
1112}
1113
Jyri Sarha864050c2017-03-24 16:47:52 +02001114static void dispc_ovl_set_burst_size(enum omap_plane_id plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001115 enum omap_burst_size burst_size)
1116{
Archit Taneja8bbe09e2012-09-10 17:31:39 +05301117 static const unsigned shifts[] = { 6, 14, 14, 14, 14, };
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001118 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001119
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001120 shift = shifts[plane];
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001121 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001122}
1123
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001124static void dispc_configure_burst_sizes(void)
1125{
1126 int i;
1127 const int burst_size = BURST_SIZE_X8;
1128
1129 /* Configure burst size always to maximum size */
Tomi Valkeinen392faa02012-10-15 15:37:22 +03001130 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001131 dispc_ovl_set_burst_size(i, burst_size);
Tomi Valkeinen5b354af2015-11-04 17:10:48 +02001132 if (dispc.feat->has_writeback)
1133 dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001134}
1135
Jyri Sarha864050c2017-03-24 16:47:52 +02001136static u32 dispc_ovl_get_burst_size(enum omap_plane_id plane)
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001137{
1138 unsigned unit = dss_feat_get_burst_size_unit();
1139 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
1140 return unit * 8;
1141}
1142
Tomi Valkeinen9c39d172017-05-04 11:19:12 +03001143static const u32 *dispc_ovl_get_color_modes(enum omap_plane_id plane)
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001144{
1145 return dss_feat_get_supported_color_modes(plane);
1146}
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001147
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02001148static int dispc_get_num_ovls(void)
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001149{
1150 return dss_feat_get_num_ovls();
1151}
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001152
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001153static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001154{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301155 if (channel == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001156 return;
1157
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301158 mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001159}
1160
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001161static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02001162 const struct omap_dss_cpr_coefs *coefs)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001163{
1164 u32 coef_r, coef_g, coef_b;
1165
Archit Tanejadd88b7a2012-06-29 14:41:30 +05301166 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001167 return;
1168
1169 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1170 FLD_VAL(coefs->rb, 9, 0);
1171 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1172 FLD_VAL(coefs->gb, 9, 0);
1173 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1174 FLD_VAL(coefs->bb, 9, 0);
1175
1176 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1177 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1178 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1179}
1180
Jyri Sarha864050c2017-03-24 16:47:52 +02001181static void dispc_ovl_set_vid_color_conv(enum omap_plane_id plane,
1182 bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001183{
1184 u32 val;
1185
1186 BUG_ON(plane == OMAP_DSS_GFX);
1187
Archit Taneja9b372c22011-05-06 11:45:49 +05301188 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001189 val = FLD_MOD(val, enable, 9, 9);
Archit Taneja9b372c22011-05-06 11:45:49 +05301190 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001191}
1192
Jyri Sarha864050c2017-03-24 16:47:52 +02001193static void dispc_ovl_enable_replication(enum omap_plane_id plane,
Archit Tanejad79db852012-09-22 12:30:17 +05301194 enum omap_overlay_caps caps, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001195{
Archit Tanejab8c095b2011-09-13 18:20:33 +05301196 static const unsigned shifts[] = { 5, 10, 10, 10 };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001197 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001198
Archit Tanejad79db852012-09-22 12:30:17 +05301199 if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
1200 return;
1201
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001202 shift = shifts[plane];
1203 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001204}
1205
Archit Taneja8f366162012-04-16 12:53:44 +05301206static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
Archit Tanejae5c09e02012-04-16 12:53:42 +05301207 u16 height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001208{
1209 u32 val;
Archit Taneja8f366162012-04-16 12:53:44 +05301210
Archit Taneja33b89922012-11-14 13:50:15 +05301211 val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) |
1212 FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0);
1213
Archit Taneja702d1442011-05-06 11:45:50 +05301214 dispc_write_reg(DISPC_SIZE_MGR(channel), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001215}
1216
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001217static void dispc_init_fifos(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001218{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001219 u32 size;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001220 int fifo;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301221 u8 start, end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001222 u32 unit;
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001223 int i;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001224
1225 unit = dss_feat_get_buffer_size_unit();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001226
Archit Tanejaa0acb552010-09-15 19:20:00 +05301227 dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001228
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001229 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1230 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001231 size *= unit;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001232 dispc.fifo_size[fifo] = size;
1233
1234 /*
1235 * By default fifos are mapped directly to overlays, fifo 0 to
1236 * ovl 0, fifo 1 to ovl 1, etc.
1237 */
1238 dispc.fifo_assignment[fifo] = fifo;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001239 }
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +03001240
1241 /*
1242 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
1243 * causes problems with certain use cases, like using the tiler in 2D
1244 * mode. The below hack swaps the fifos of GFX and WB planes, thus
1245 * giving GFX plane a larger fifo. WB but should work fine with a
1246 * smaller fifo.
1247 */
1248 if (dispc.feat->gfx_fifo_workaround) {
1249 u32 v;
1250
1251 v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
1252
1253 v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
1254 v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
1255 v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
1256 v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
1257
1258 dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
1259
1260 dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
1261 dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
1262 }
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001263
1264 /*
1265 * Setup default fifo thresholds.
1266 */
1267 for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
1268 u32 low, high;
1269 const bool use_fifomerge = false;
1270 const bool manual_update = false;
1271
1272 dispc_ovl_compute_fifo_thresholds(i, &low, &high,
1273 use_fifomerge, manual_update);
1274
1275 dispc_ovl_set_fifo_threshold(i, low, high);
1276 }
Tomi Valkeinen65e116e2015-11-04 17:10:49 +02001277
1278 if (dispc.feat->has_writeback) {
1279 u32 low, high;
1280 const bool use_fifomerge = false;
1281 const bool manual_update = false;
1282
1283 dispc_ovl_compute_fifo_thresholds(OMAP_DSS_WB, &low, &high,
1284 use_fifomerge, manual_update);
1285
1286 dispc_ovl_set_fifo_threshold(OMAP_DSS_WB, low, high);
1287 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001288}
1289
Jyri Sarha864050c2017-03-24 16:47:52 +02001290static u32 dispc_ovl_get_fifo_size(enum omap_plane_id plane)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001291{
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001292 int fifo;
1293 u32 size = 0;
1294
1295 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1296 if (dispc.fifo_assignment[fifo] == plane)
1297 size += dispc.fifo_size[fifo];
1298 }
1299
1300 return size;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001301}
1302
Jyri Sarha864050c2017-03-24 16:47:52 +02001303void dispc_ovl_set_fifo_threshold(enum omap_plane_id plane, u32 low,
1304 u32 high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001305{
Archit Tanejaa0acb552010-09-15 19:20:00 +05301306 u8 hi_start, hi_end, lo_start, lo_end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001307 u32 unit;
1308
1309 unit = dss_feat_get_buffer_size_unit();
1310
1311 WARN_ON(low % unit != 0);
1312 WARN_ON(high % unit != 0);
1313
1314 low /= unit;
1315 high /= unit;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301316
Archit Taneja9b372c22011-05-06 11:45:49 +05301317 dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1318 dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
1319
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001320 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001321 plane,
Archit Taneja9b372c22011-05-06 11:45:49 +05301322 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001323 lo_start, lo_end) * unit,
Archit Taneja9b372c22011-05-06 11:45:49 +05301324 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001325 hi_start, hi_end) * unit,
1326 low * unit, high * unit);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001327
Archit Taneja9b372c22011-05-06 11:45:49 +05301328 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
Archit Tanejaa0acb552010-09-15 19:20:00 +05301329 FLD_VAL(high, hi_start, hi_end) |
1330 FLD_VAL(low, lo_start, lo_end));
Archit Taneja8bc65552013-12-17 16:40:21 +05301331
1332 /*
1333 * configure the preload to the pipeline's high threhold, if HT it's too
1334 * large for the preload field, set the threshold to the maximum value
1335 * that can be held by the preload register
1336 */
1337 if (dss_has_feature(FEAT_PRELOAD) && dispc.feat->set_max_preload &&
1338 plane != OMAP_DSS_WB)
1339 dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001340}
1341
1342void dispc_enable_fifomerge(bool enable)
1343{
Tomi Valkeinene6b0f882012-01-13 13:24:04 +02001344 if (!dss_has_feature(FEAT_FIFO_MERGE)) {
1345 WARN_ON(enable);
1346 return;
1347 }
1348
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001349 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1350 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001351}
1352
Jyri Sarha864050c2017-03-24 16:47:52 +02001353void dispc_ovl_compute_fifo_thresholds(enum omap_plane_id plane,
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001354 u32 *fifo_low, u32 *fifo_high, bool use_fifomerge,
1355 bool manual_update)
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001356{
1357 /*
1358 * All sizes are in bytes. Both the buffer and burst are made of
1359 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1360 */
1361
1362 unsigned buf_unit = dss_feat_get_buffer_size_unit();
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001363 unsigned ovl_fifo_size, total_fifo_size, burst_size;
1364 int i;
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001365
1366 burst_size = dispc_ovl_get_burst_size(plane);
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001367 ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001368
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001369 if (use_fifomerge) {
1370 total_fifo_size = 0;
Tomi Valkeinen392faa02012-10-15 15:37:22 +03001371 for (i = 0; i < dss_feat_get_num_ovls(); ++i)
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001372 total_fifo_size += dispc_ovl_get_fifo_size(i);
1373 } else {
1374 total_fifo_size = ovl_fifo_size;
1375 }
1376
1377 /*
1378 * We use the same low threshold for both fifomerge and non-fifomerge
1379 * cases, but for fifomerge we calculate the high threshold using the
1380 * combined fifo size
1381 */
1382
Tomi Valkeinen3568f2a2012-05-15 15:31:01 +03001383 if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001384 *fifo_low = ovl_fifo_size - burst_size * 2;
1385 *fifo_high = total_fifo_size - burst_size;
Archit Taneja8bbe09e2012-09-10 17:31:39 +05301386 } else if (plane == OMAP_DSS_WB) {
1387 /*
1388 * Most optimal configuration for writeback is to push out data
1389 * to the interconnect the moment writeback pushes enough pixels
1390 * in the FIFO to form a burst
1391 */
1392 *fifo_low = 0;
1393 *fifo_high = burst_size;
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001394 } else {
1395 *fifo_low = ovl_fifo_size - burst_size;
1396 *fifo_high = total_fifo_size - buf_unit;
1397 }
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001398}
1399
Jyri Sarha864050c2017-03-24 16:47:52 +02001400static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable)
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001401{
1402 int bit;
1403
1404 if (plane == OMAP_DSS_GFX)
1405 bit = 14;
1406 else
1407 bit = 23;
1408
1409 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
1410}
1411
Jyri Sarha864050c2017-03-24 16:47:52 +02001412static void dispc_ovl_set_mflag_threshold(enum omap_plane_id plane,
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001413 int low, int high)
1414{
1415 dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane),
1416 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
1417}
1418
1419static void dispc_init_mflag(void)
1420{
1421 int i;
1422
Tomi Valkeinenfe59e5c2014-11-19 12:50:16 +02001423 /*
1424 * HACK: NV12 color format and MFLAG seem to have problems working
1425 * together: using two displays, and having an NV12 overlay on one of
1426 * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
1427 * Changing MFLAG thresholds and PRELOAD to certain values seem to
1428 * remove the errors, but there doesn't seem to be a clear logic on
1429 * which values work and which not.
1430 *
1431 * As a work-around, set force MFLAG to always on.
1432 */
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001433 dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE,
Tomi Valkeinenfe59e5c2014-11-19 12:50:16 +02001434 (1 << 0) | /* MFLAG_CTRL = force always on */
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001435 (0 << 2)); /* MFLAG_START = disable */
1436
1437 for (i = 0; i < dss_feat_get_num_ovls(); ++i) {
1438 u32 size = dispc_ovl_get_fifo_size(i);
1439 u32 unit = dss_feat_get_buffer_size_unit();
1440 u32 low, high;
1441
1442 dispc_ovl_set_mflag(i, true);
1443
1444 /*
1445 * Simulation team suggests below thesholds:
1446 * HT = fifosize * 5 / 8;
1447 * LT = fifosize * 4 / 8;
1448 */
1449
1450 low = size * 4 / 8 / unit;
1451 high = size * 5 / 8 / unit;
1452
1453 dispc_ovl_set_mflag_threshold(i, low, high);
1454 }
Tomi Valkeinenecb0b362015-11-04 17:10:50 +02001455
1456 if (dispc.feat->has_writeback) {
1457 u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB);
1458 u32 unit = dss_feat_get_buffer_size_unit();
1459 u32 low, high;
1460
1461 dispc_ovl_set_mflag(OMAP_DSS_WB, true);
1462
1463 /*
1464 * Simulation team suggests below thesholds:
1465 * HT = fifosize * 5 / 8;
1466 * LT = fifosize * 4 / 8;
1467 */
1468
1469 low = size * 4 / 8 / unit;
1470 high = size * 5 / 8 / unit;
1471
1472 dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high);
1473 }
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001474}
1475
Jyri Sarha864050c2017-03-24 16:47:52 +02001476static void dispc_ovl_set_fir(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301477 int hinc, int vinc,
1478 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001479{
1480 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001481
Amber Jain0d66cbb2011-05-19 19:47:54 +05301482 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1483 u8 hinc_start, hinc_end, vinc_start, vinc_end;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301484
Amber Jain0d66cbb2011-05-19 19:47:54 +05301485 dss_feat_get_reg_field(FEAT_REG_FIRHINC,
1486 &hinc_start, &hinc_end);
1487 dss_feat_get_reg_field(FEAT_REG_FIRVINC,
1488 &vinc_start, &vinc_end);
1489 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1490 FLD_VAL(hinc, hinc_start, hinc_end);
Archit Tanejaa0acb552010-09-15 19:20:00 +05301491
Amber Jain0d66cbb2011-05-19 19:47:54 +05301492 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1493 } else {
1494 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1495 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1496 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001497}
1498
Jyri Sarha864050c2017-03-24 16:47:52 +02001499static void dispc_ovl_set_vid_accu0(enum omap_plane_id plane, int haccu,
1500 int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001501{
1502 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301503 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001504
Archit Taneja87a74842011-03-02 11:19:50 +05301505 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1506 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1507
1508 val = FLD_VAL(vaccu, vert_start, vert_end) |
1509 FLD_VAL(haccu, hor_start, hor_end);
1510
Archit Taneja9b372c22011-05-06 11:45:49 +05301511 dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001512}
1513
Jyri Sarha864050c2017-03-24 16:47:52 +02001514static void dispc_ovl_set_vid_accu1(enum omap_plane_id plane, int haccu,
1515 int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001516{
1517 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301518 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001519
Archit Taneja87a74842011-03-02 11:19:50 +05301520 dss_feat_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1521 dss_feat_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
1522
1523 val = FLD_VAL(vaccu, vert_start, vert_end) |
1524 FLD_VAL(haccu, hor_start, hor_end);
1525
Archit Taneja9b372c22011-05-06 11:45:49 +05301526 dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001527}
1528
Jyri Sarha864050c2017-03-24 16:47:52 +02001529static void dispc_ovl_set_vid_accu2_0(enum omap_plane_id plane, int haccu,
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001530 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301531{
1532 u32 val;
1533
1534 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1535 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1536}
1537
Jyri Sarha864050c2017-03-24 16:47:52 +02001538static void dispc_ovl_set_vid_accu2_1(enum omap_plane_id plane, int haccu,
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001539 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301540{
1541 u32 val;
1542
1543 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1544 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1545}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001546
Jyri Sarha864050c2017-03-24 16:47:52 +02001547static void dispc_ovl_set_scale_param(enum omap_plane_id plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001548 u16 orig_width, u16 orig_height,
1549 u16 out_width, u16 out_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301550 bool five_taps, u8 rotation,
1551 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001552{
Amber Jain0d66cbb2011-05-19 19:47:54 +05301553 int fir_hinc, fir_vinc;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001554
Amber Jained14a3c2011-05-19 19:47:51 +05301555 fir_hinc = 1024 * orig_width / out_width;
1556 fir_vinc = 1024 * orig_height / out_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001557
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +05301558 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1559 color_comp);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001560 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301561}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001562
Jyri Sarha864050c2017-03-24 16:47:52 +02001563static void dispc_ovl_set_accu_uv(enum omap_plane_id plane,
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301564 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001565 bool ilace, u32 fourcc, u8 rotation)
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301566{
1567 int h_accu2_0, h_accu2_1;
1568 int v_accu2_0, v_accu2_1;
1569 int chroma_hinc, chroma_vinc;
1570 int idx;
1571
1572 struct accu {
1573 s8 h0_m, h0_n;
1574 s8 h1_m, h1_n;
1575 s8 v0_m, v0_n;
1576 s8 v1_m, v1_n;
1577 };
1578
1579 const struct accu *accu_table;
1580 const struct accu *accu_val;
1581
1582 static const struct accu accu_nv12[4] = {
1583 { 0, 1, 0, 1 , -1, 2, 0, 1 },
1584 { 1, 2, -3, 4 , 0, 1, 0, 1 },
1585 { -1, 1, 0, 1 , -1, 2, 0, 1 },
1586 { -1, 2, -1, 2 , -1, 1, 0, 1 },
1587 };
1588
1589 static const struct accu accu_nv12_ilace[4] = {
1590 { 0, 1, 0, 1 , -3, 4, -1, 4 },
1591 { -1, 4, -3, 4 , 0, 1, 0, 1 },
1592 { -1, 1, 0, 1 , -1, 4, -3, 4 },
1593 { -3, 4, -3, 4 , -1, 1, 0, 1 },
1594 };
1595
1596 static const struct accu accu_yuv[4] = {
1597 { 0, 1, 0, 1, 0, 1, 0, 1 },
1598 { 0, 1, 0, 1, 0, 1, 0, 1 },
1599 { -1, 1, 0, 1, 0, 1, 0, 1 },
1600 { 0, 1, 0, 1, -1, 1, 0, 1 },
1601 };
1602
1603 switch (rotation) {
1604 case OMAP_DSS_ROT_0:
1605 idx = 0;
1606 break;
1607 case OMAP_DSS_ROT_90:
1608 idx = 1;
1609 break;
1610 case OMAP_DSS_ROT_180:
1611 idx = 2;
1612 break;
1613 case OMAP_DSS_ROT_270:
1614 idx = 3;
1615 break;
1616 default:
1617 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001618 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301619 }
1620
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001621 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001622 case DRM_FORMAT_NV12:
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301623 if (ilace)
1624 accu_table = accu_nv12_ilace;
1625 else
1626 accu_table = accu_nv12;
1627 break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001628 case DRM_FORMAT_YUYV:
1629 case DRM_FORMAT_UYVY:
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301630 accu_table = accu_yuv;
1631 break;
1632 default:
1633 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001634 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301635 }
1636
1637 accu_val = &accu_table[idx];
1638
1639 chroma_hinc = 1024 * orig_width / out_width;
1640 chroma_vinc = 1024 * orig_height / out_height;
1641
1642 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1643 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1644 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1645 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1646
1647 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1648 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1649}
1650
Jyri Sarha864050c2017-03-24 16:47:52 +02001651static void dispc_ovl_set_scaling_common(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301652 u16 orig_width, u16 orig_height,
1653 u16 out_width, u16 out_height,
1654 bool ilace, bool five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001655 bool fieldmode, u32 fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301656 u8 rotation)
1657{
1658 int accu0 = 0;
1659 int accu1 = 0;
1660 u32 l;
1661
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001662 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301663 out_width, out_height, five_taps,
1664 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
Archit Taneja9b372c22011-05-06 11:45:49 +05301665 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001666
Archit Taneja87a74842011-03-02 11:19:50 +05301667 /* RESIZEENABLE and VERTICALTAPS */
1668 l &= ~((0x3 << 5) | (0x1 << 21));
Amber Jained14a3c2011-05-19 19:47:51 +05301669 l |= (orig_width != out_width) ? (1 << 5) : 0;
1670 l |= (orig_height != out_height) ? (1 << 6) : 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001671 l |= five_taps ? (1 << 21) : 0;
Archit Taneja87a74842011-03-02 11:19:50 +05301672
1673 /* VRESIZECONF and HRESIZECONF */
1674 if (dss_has_feature(FEAT_RESIZECONF)) {
1675 l &= ~(0x3 << 7);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301676 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1677 l |= (orig_height <= out_height) ? 0 : (1 << 8);
Archit Taneja87a74842011-03-02 11:19:50 +05301678 }
1679
1680 /* LINEBUFFERSPLIT */
1681 if (dss_has_feature(FEAT_LINEBUFFERSPLIT)) {
1682 l &= ~(0x1 << 22);
1683 l |= five_taps ? (1 << 22) : 0;
1684 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001685
Archit Taneja9b372c22011-05-06 11:45:49 +05301686 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001687
1688 /*
1689 * field 0 = even field = bottom field
1690 * field 1 = odd field = top field
1691 */
1692 if (ilace && !fieldmode) {
1693 accu1 = 0;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301694 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001695 if (accu0 >= 1024/2) {
1696 accu1 = 1024/2;
1697 accu0 -= accu1;
1698 }
1699 }
1700
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001701 dispc_ovl_set_vid_accu0(plane, 0, accu0);
1702 dispc_ovl_set_vid_accu1(plane, 0, accu1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001703}
1704
Jyri Sarha864050c2017-03-24 16:47:52 +02001705static void dispc_ovl_set_scaling_uv(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301706 u16 orig_width, u16 orig_height,
1707 u16 out_width, u16 out_height,
1708 bool ilace, bool five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001709 bool fieldmode, u32 fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301710 u8 rotation)
1711{
1712 int scale_x = out_width != orig_width;
1713 int scale_y = out_height != orig_height;
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05001714 bool chroma_upscale = plane != OMAP_DSS_WB;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301715
1716 if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE))
1717 return;
Tomi Valkeinen5edec142017-05-04 09:13:32 +03001718
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001719 if (!format_is_yuv(fourcc)) {
Amber Jain0d66cbb2011-05-19 19:47:54 +05301720 /* reset chroma resampling for RGB formats */
Archit Taneja2a5561b2012-07-16 16:37:45 +05301721 if (plane != OMAP_DSS_WB)
1722 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301723 return;
1724 }
Tomi Valkeinen36377352012-05-15 15:54:15 +03001725
1726 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001727 out_height, ilace, fourcc, rotation);
Tomi Valkeinen36377352012-05-15 15:54:15 +03001728
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001729 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001730 case DRM_FORMAT_NV12:
Archit Taneja20fbb502012-08-22 17:04:48 +05301731 if (chroma_upscale) {
1732 /* UV is subsampled by 2 horizontally and vertically */
1733 orig_height >>= 1;
1734 orig_width >>= 1;
1735 } else {
1736 /* UV is downsampled by 2 horizontally and vertically */
1737 orig_height <<= 1;
1738 orig_width <<= 1;
1739 }
1740
Amber Jain0d66cbb2011-05-19 19:47:54 +05301741 break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001742 case DRM_FORMAT_YUYV:
1743 case DRM_FORMAT_UYVY:
Archit Taneja20fbb502012-08-22 17:04:48 +05301744 /* For YUV422 with 90/270 rotation, we don't upsample chroma */
Amber Jain0d66cbb2011-05-19 19:47:54 +05301745 if (rotation == OMAP_DSS_ROT_0 ||
Archit Taneja20fbb502012-08-22 17:04:48 +05301746 rotation == OMAP_DSS_ROT_180) {
1747 if (chroma_upscale)
1748 /* UV is subsampled by 2 horizontally */
1749 orig_width >>= 1;
1750 else
1751 /* UV is downsampled by 2 horizontally */
1752 orig_width <<= 1;
1753 }
1754
Amber Jain0d66cbb2011-05-19 19:47:54 +05301755 /* must use FIR for YUV422 if rotated */
1756 if (rotation != OMAP_DSS_ROT_0)
1757 scale_x = scale_y = true;
Archit Taneja20fbb502012-08-22 17:04:48 +05301758
Amber Jain0d66cbb2011-05-19 19:47:54 +05301759 break;
1760 default:
1761 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001762 return;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301763 }
1764
1765 if (out_width != orig_width)
1766 scale_x = true;
1767 if (out_height != orig_height)
1768 scale_y = true;
1769
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001770 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301771 out_width, out_height, five_taps,
1772 rotation, DISPC_COLOR_COMPONENT_UV);
1773
Archit Taneja2a5561b2012-07-16 16:37:45 +05301774 if (plane != OMAP_DSS_WB)
1775 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1776 (scale_x || scale_y) ? 1 : 0, 8, 8);
1777
Amber Jain0d66cbb2011-05-19 19:47:54 +05301778 /* set H scaling */
1779 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1780 /* set V scaling */
1781 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301782}
1783
Jyri Sarha864050c2017-03-24 16:47:52 +02001784static void dispc_ovl_set_scaling(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301785 u16 orig_width, u16 orig_height,
1786 u16 out_width, u16 out_height,
1787 bool ilace, bool five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001788 bool fieldmode, u32 fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301789 u8 rotation)
1790{
1791 BUG_ON(plane == OMAP_DSS_GFX);
1792
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001793 dispc_ovl_set_scaling_common(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301794 orig_width, orig_height,
1795 out_width, out_height,
1796 ilace, five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001797 fieldmode, fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301798 rotation);
1799
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001800 dispc_ovl_set_scaling_uv(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301801 orig_width, orig_height,
1802 out_width, out_height,
1803 ilace, five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001804 fieldmode, fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301805 rotation);
1806}
1807
Jyri Sarha273ffea2017-03-24 16:47:53 +02001808static void dispc_ovl_set_rotation_attrs(enum omap_plane_id plane, u8 rotation,
Archit Tanejac35eeb22013-03-26 19:15:24 +05301809 enum omap_dss_rotation_type rotation_type,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001810 bool mirroring, u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001811{
Archit Taneja87a74842011-03-02 11:19:50 +05301812 bool row_repeat = false;
1813 int vidrot = 0;
1814
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001815 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) {
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001816
1817 if (mirroring) {
1818 switch (rotation) {
1819 case OMAP_DSS_ROT_0:
1820 vidrot = 2;
1821 break;
1822 case OMAP_DSS_ROT_90:
1823 vidrot = 1;
1824 break;
1825 case OMAP_DSS_ROT_180:
1826 vidrot = 0;
1827 break;
1828 case OMAP_DSS_ROT_270:
1829 vidrot = 3;
1830 break;
1831 }
1832 } else {
1833 switch (rotation) {
1834 case OMAP_DSS_ROT_0:
1835 vidrot = 0;
1836 break;
1837 case OMAP_DSS_ROT_90:
1838 vidrot = 1;
1839 break;
1840 case OMAP_DSS_ROT_180:
1841 vidrot = 2;
1842 break;
1843 case OMAP_DSS_ROT_270:
1844 vidrot = 3;
1845 break;
1846 }
1847 }
1848
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001849 if (rotation == OMAP_DSS_ROT_90 || rotation == OMAP_DSS_ROT_270)
Archit Taneja87a74842011-03-02 11:19:50 +05301850 row_repeat = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001851 else
Archit Taneja87a74842011-03-02 11:19:50 +05301852 row_repeat = false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001853 }
Archit Taneja87a74842011-03-02 11:19:50 +05301854
Tomi Valkeinen3397cc62015-04-09 13:51:30 +03001855 /*
1856 * OMAP4/5 Errata i631:
1857 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
1858 * rows beyond the framebuffer, which may cause OCP error.
1859 */
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001860 if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER)
Tomi Valkeinen3397cc62015-04-09 13:51:30 +03001861 vidrot = 1;
1862
Archit Taneja9b372c22011-05-06 11:45:49 +05301863 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
Archit Taneja87a74842011-03-02 11:19:50 +05301864 if (dss_has_feature(FEAT_ROWREPEATENABLE))
Archit Taneja9b372c22011-05-06 11:45:49 +05301865 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1866 row_repeat ? 1 : 0, 18, 18);
Archit Tanejac35eeb22013-03-26 19:15:24 +05301867
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001868 if (dss_feat_color_mode_supported(plane, DRM_FORMAT_NV12)) {
Tomi Valkeinen6d862782016-08-29 11:15:49 +03001869 bool doublestride =
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001870 fourcc == DRM_FORMAT_NV12 &&
Tomi Valkeinen6d862782016-08-29 11:15:49 +03001871 rotation_type == OMAP_DSS_ROT_TILER &&
1872 (rotation == OMAP_DSS_ROT_0 || rotation == OMAP_DSS_ROT_180);
1873
Archit Tanejac35eeb22013-03-26 19:15:24 +05301874 /* DOUBLESTRIDE */
1875 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
1876 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001877}
1878
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001879static int color_mode_to_bpp(u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001880{
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001881 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001882 case DRM_FORMAT_NV12:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001883 return 8;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001884 case DRM_FORMAT_RGBX4444:
1885 case DRM_FORMAT_RGB565:
1886 case DRM_FORMAT_ARGB4444:
1887 case DRM_FORMAT_YUYV:
1888 case DRM_FORMAT_UYVY:
1889 case DRM_FORMAT_RGBA4444:
1890 case DRM_FORMAT_XRGB4444:
1891 case DRM_FORMAT_ARGB1555:
1892 case DRM_FORMAT_XRGB1555:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001893 return 16;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001894 case DRM_FORMAT_RGB888:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001895 return 24;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001896 case DRM_FORMAT_XRGB8888:
1897 case DRM_FORMAT_ARGB8888:
1898 case DRM_FORMAT_RGBA8888:
1899 case DRM_FORMAT_RGBX8888:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001900 return 32;
1901 default:
1902 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001903 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001904 }
1905}
1906
1907static s32 pixinc(int pixels, u8 ps)
1908{
1909 if (pixels == 1)
1910 return 1;
1911 else if (pixels > 1)
1912 return 1 + (pixels - 1) * ps;
1913 else if (pixels < 0)
1914 return 1 - (-pixels + 1) * ps;
1915 else
1916 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001917 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001918}
1919
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03001920static void calc_offset(u16 screen_width, u16 width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001921 u32 fourcc, bool fieldmode,
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301922 unsigned int field_offset, unsigned *offset0, unsigned *offset1,
1923 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim)
1924{
1925 u8 ps;
1926
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001927 ps = color_mode_to_bpp(fourcc) / 8;
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301928
1929 DSSDBG("scrw %d, width %d\n", screen_width, width);
1930
1931 /*
1932 * field 0 = even field = bottom field
1933 * field 1 = odd field = top field
1934 */
Tomi Valkeinen185e23e2017-05-03 15:01:10 +03001935 *offset0 = field_offset * screen_width * ps;
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301936 *offset1 = 0;
Tomi Valkeinen185e23e2017-05-03 15:01:10 +03001937
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301938 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
1939 (fieldmode ? screen_width : 0), ps);
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001940 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY)
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301941 *pix_inc = pixinc(x_predecim, 2 * ps);
1942 else
1943 *pix_inc = pixinc(x_predecim, ps);
1944}
1945
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301946/*
1947 * This function is used to avoid synclosts in OMAP3, because of some
1948 * undocumented horizontal position and timing related limitations.
1949 */
Tomi Valkeinen465ec132012-10-19 15:40:24 +03001950static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03001951 const struct videomode *vm, u16 pos_x,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02001952 u16 width, u16 height, u16 out_width, u16 out_height,
1953 bool five_taps)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301954{
Tomi Valkeinen230edc02012-11-05 14:40:19 +02001955 const int ds = DIV_ROUND_UP(height, out_height);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05301956 unsigned long nonactive;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301957 static const u8 limits[3] = { 8, 10, 20 };
1958 u64 val, blank;
1959 int i;
1960
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03001961 nonactive = vm->hactive + vm->hfront_porch + vm->hsync_len +
1962 vm->hback_porch - out_width;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301963
1964 i = 0;
1965 if (out_height < height)
1966 i++;
1967 if (out_width < width)
1968 i++;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03001969 blank = div_u64((u64)(vm->hback_porch + vm->hsync_len + vm->hfront_porch) *
Peter Ujfalusi0a30e152016-09-22 14:06:49 +03001970 lclk, pclk);
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301971 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
1972 if (blank <= limits[i])
1973 return -EINVAL;
1974
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02001975 /* FIXME add checks for 3-tap filter once the limitations are known */
1976 if (!five_taps)
1977 return 0;
1978
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301979 /*
1980 * Pixel data should be prepared before visible display point starts.
1981 * So, atleast DS-2 lines must have already been fetched by DISPC
1982 * during nonactive - pos_x period.
1983 */
1984 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
1985 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
Tomi Valkeinen230edc02012-11-05 14:40:19 +02001986 val, max(0, ds - 2) * width);
1987 if (val < max(0, ds - 2) * width)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301988 return -EINVAL;
1989
1990 /*
1991 * All lines need to be refilled during the nonactive period of which
1992 * only one line can be loaded during the active period. So, atleast
1993 * DS - 1 lines should be loaded during nonactive period.
1994 */
1995 val = div_u64((u64)nonactive * lclk, pclk);
1996 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
Tomi Valkeinen230edc02012-11-05 14:40:19 +02001997 val, max(0, ds - 1) * width);
1998 if (val < max(0, ds - 1) * width)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05301999 return -EINVAL;
2000
2001 return 0;
2002}
2003
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002004static unsigned long calc_core_clk_five_taps(unsigned long pclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002005 const struct videomode *vm, u16 width,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302006 u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002007 u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002008{
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302009 u32 core_clk = 0;
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302010 u64 tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002011
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302012 if (height <= out_height && width <= out_width)
2013 return (unsigned long) pclk;
2014
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002015 if (height > out_height) {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002016 unsigned int ppl = vm->hactive;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002017
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002018 tmp = (u64)pclk * height * out_width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002019 do_div(tmp, 2 * out_height * ppl);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302020 core_clk = tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002021
Ville Syrjälä2d9c5592010-01-08 11:56:41 +02002022 if (height > 2 * out_height) {
2023 if (ppl == out_width)
2024 return 0;
2025
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002026 tmp = (u64)pclk * (height - 2 * out_height) * out_width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002027 do_div(tmp, 2 * out_height * (ppl - out_width));
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302028 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002029 }
2030 }
2031
2032 if (width > out_width) {
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002033 tmp = (u64)pclk * width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002034 do_div(tmp, out_width);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302035 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002036
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002037 if (fourcc == DRM_FORMAT_XRGB8888)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302038 core_clk <<= 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002039 }
2040
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302041 return core_clk;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002042}
2043
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002044static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302045 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302046{
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302047 if (height > out_height && width > out_width)
2048 return pclk * 4;
2049 else
2050 return pclk * 2;
2051}
2052
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002053static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302054 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002055{
2056 unsigned int hf, vf;
2057
2058 /*
2059 * FIXME how to determine the 'A' factor
2060 * for the no downscaling case ?
2061 */
2062
2063 if (width > 3 * out_width)
2064 hf = 4;
2065 else if (width > 2 * out_width)
2066 hf = 3;
2067 else if (width > out_width)
2068 hf = 2;
2069 else
2070 hf = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002071 if (height > out_height)
2072 vf = 2;
2073 else
2074 vf = 1;
2075
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302076 return pclk * vf * hf;
2077}
2078
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002079static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302080 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302081{
Archit Taneja8ba85302012-09-26 17:00:37 +05302082 /*
2083 * If the overlay/writeback is in mem to mem mode, there are no
2084 * downscaling limitations with respect to pixel clock, return 1 as
2085 * required core clock to represent that we have sufficient enough
2086 * core clock to do maximum downscaling
2087 */
2088 if (mem_to_mem)
2089 return 1;
2090
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302091 if (width > out_width)
2092 return DIV_ROUND_UP(pclk, out_width) * width;
2093 else
2094 return pclk;
2095}
2096
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002097static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002098 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302099 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002100 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302101 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302102 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302103{
2104 int error;
2105 u16 in_width, in_height;
2106 int min_factor = min(*decim_x, *decim_y);
2107 const int maxsinglelinewidth =
2108 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302109
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302110 *five_taps = false;
2111
2112 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002113 in_height = height / *decim_y;
2114 in_width = width / *decim_x;
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002115 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302116 in_height, out_width, out_height, mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302117 error = (in_width > maxsinglelinewidth || !*core_clk ||
2118 *core_clk > dispc_core_clk_rate());
2119 if (error) {
2120 if (*decim_x == *decim_y) {
2121 *decim_x = min_factor;
2122 ++*decim_y;
2123 } else {
2124 swap(*decim_x, *decim_y);
2125 if (*decim_x < *decim_y)
2126 ++*decim_x;
2127 }
2128 }
2129 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2130
Tomi Valkeinen3ce17b42015-04-10 12:48:37 +03002131 if (error) {
2132 DSSERR("failed to find scaling settings\n");
2133 return -EINVAL;
2134 }
2135
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302136 if (in_width > maxsinglelinewidth) {
2137 DSSERR("Cannot scale max input width exceeded");
2138 return -EINVAL;
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302139 }
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302140 return 0;
2141}
2142
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002143static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002144 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302145 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002146 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302147 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302148 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302149{
2150 int error;
2151 u16 in_width, in_height;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302152 const int maxsinglelinewidth =
2153 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
2154
2155 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002156 in_height = height / *decim_y;
2157 in_width = width / *decim_x;
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002158 *five_taps = in_height > out_height;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302159
2160 if (in_width > maxsinglelinewidth)
2161 if (in_height > out_height &&
2162 in_height < out_height * 2)
2163 *five_taps = false;
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002164again:
2165 if (*five_taps)
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002166 *core_clk = calc_core_clk_five_taps(pclk, vm,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002167 in_width, in_height, out_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002168 out_height, fourcc);
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002169 else
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002170 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302171 in_height, out_width, out_height,
2172 mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302173
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002174 error = check_horiz_timing_omap3(pclk, lclk, vm,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002175 pos_x, in_width, in_height, out_width,
2176 out_height, *five_taps);
2177 if (error && *five_taps) {
2178 *five_taps = false;
2179 goto again;
2180 }
2181
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302182 error = (error || in_width > maxsinglelinewidth * 2 ||
2183 (in_width > maxsinglelinewidth && *five_taps) ||
2184 !*core_clk || *core_clk > dispc_core_clk_rate());
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002185
2186 if (!error) {
2187 /* verify that we're inside the limits of scaler */
2188 if (in_width / 4 > out_width)
2189 error = 1;
2190
2191 if (*five_taps) {
2192 if (in_height / 4 > out_height)
2193 error = 1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302194 } else {
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002195 if (in_height / 2 > out_height)
2196 error = 1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302197 }
2198 }
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002199
Tomi Valkeinen7059e3d2015-04-10 12:48:38 +03002200 if (error)
2201 ++*decim_y;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302202 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2203
Tomi Valkeinen3ce17b42015-04-10 12:48:37 +03002204 if (error) {
2205 DSSERR("failed to find scaling settings\n");
2206 return -EINVAL;
2207 }
2208
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002209 if (check_horiz_timing_omap3(pclk, lclk, vm, pos_x, in_width,
Tomi Valkeinenf5a73482015-03-17 15:31:09 +02002210 in_height, out_width, out_height, *five_taps)) {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302211 DSSERR("horizontal timing too tight\n");
2212 return -EINVAL;
2213 }
2214
2215 if (in_width > (maxsinglelinewidth * 2)) {
2216 DSSERR("Cannot setup scaling");
2217 DSSERR("width exceeds maximum width possible");
2218 return -EINVAL;
2219 }
2220
2221 if (in_width > maxsinglelinewidth && *five_taps) {
2222 DSSERR("cannot setup scaling with five taps");
2223 return -EINVAL;
2224 }
2225 return 0;
2226}
2227
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002228static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002229 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302230 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002231 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302232 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302233 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302234{
2235 u16 in_width, in_width_max;
2236 int decim_x_min = *decim_x;
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002237 u16 in_height = height / *decim_y;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302238 const int maxsinglelinewidth =
2239 dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH);
Archit Taneja8ba85302012-09-26 17:00:37 +05302240 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302241
Archit Taneja5d501082012-11-07 11:45:02 +05302242 if (mem_to_mem) {
2243 in_width_max = out_width * maxdownscale;
2244 } else {
Archit Taneja8ba85302012-09-26 17:00:37 +05302245 in_width_max = dispc_core_clk_rate() /
2246 DIV_ROUND_UP(pclk, out_width);
Archit Taneja5d501082012-11-07 11:45:02 +05302247 }
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302248
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302249 *decim_x = DIV_ROUND_UP(width, in_width_max);
2250
2251 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2252 if (*decim_x > *x_predecim)
2253 return -EINVAL;
2254
2255 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002256 in_width = width / *decim_x;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302257 } while (*decim_x <= *x_predecim &&
2258 in_width > maxsinglelinewidth && ++*decim_x);
2259
2260 if (in_width > maxsinglelinewidth) {
2261 DSSERR("Cannot scale width exceeds max line width");
2262 return -EINVAL;
2263 }
2264
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002265 if (*decim_x > 4 && fourcc != DRM_FORMAT_NV12) {
Jyri Sarha1b30ab02017-02-08 16:08:06 +02002266 /*
2267 * Let's disable all scaling that requires horizontal
2268 * decimation with higher factor than 4, until we have
2269 * better estimates of what we can and can not
2270 * do. However, NV12 color format appears to work Ok
2271 * with all decimation factors.
2272 *
2273 * When decimating horizontally by more that 4 the dss
2274 * is not able to fetch the data in burst mode. When
2275 * this happens it is hard to tell if there enough
2276 * bandwidth. Despite what theory says this appears to
2277 * be true also for 16-bit color formats.
2278 */
2279 DSSERR("Not enough bandwidth, too much downscaling (x-decimation factor %d > 4)", *decim_x);
2280
2281 return -EINVAL;
2282 }
2283
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002284 *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
Archit Taneja8ba85302012-09-26 17:00:37 +05302285 out_width, out_height, mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302286 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002287}
2288
Tomi Valkeinene4c5ae72015-04-10 12:48:39 +03002289#define DIV_FRAC(dividend, divisor) \
2290 ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
2291
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002292static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302293 enum omap_overlay_caps caps,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002294 const struct videomode *vm,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302295 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002296 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatrad557a9c2012-09-24 12:08:27 +05302297 int *x_predecim, int *y_predecim, u16 pos_x,
Archit Taneja8ba85302012-09-26 17:00:37 +05302298 enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302299{
Archit Taneja0373cac2011-09-08 13:25:17 +05302300 const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE);
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302301 const int max_decim_limit = 16;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302302 unsigned long core_clk = 0;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302303 int decim_x, decim_y, ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302304
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002305 if (width == out_width && height == out_height)
2306 return 0;
2307
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002308 if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) {
Tomi Valkeinen4e1d3ca2014-10-03 15:14:09 +00002309 DSSERR("cannot calculate scaling settings: pclk is zero\n");
2310 return -EINVAL;
2311 }
2312
Archit Taneja5b54ed32012-09-26 16:55:27 +05302313 if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002314 return -EINVAL;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302315
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002316 if (mem_to_mem) {
Archit Taneja1c031442012-11-07 11:45:03 +05302317 *x_predecim = *y_predecim = 1;
2318 } else {
2319 *x_predecim = max_decim_limit;
2320 *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
2321 dss_has_feature(FEAT_BURST_2D)) ?
2322 2 : max_decim_limit;
2323 }
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302324
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302325 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2326 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2327
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302328 if (decim_x > *x_predecim || out_width > width * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302329 return -EINVAL;
2330
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302331 if (decim_y > *y_predecim || out_height > height * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302332 return -EINVAL;
2333
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002334 ret = dispc.feat->calc_scaling(pclk, lclk, vm, width, height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002335 out_width, out_height, fourcc, five_taps,
Archit Taneja8ba85302012-09-26 17:00:37 +05302336 x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
2337 mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302338 if (ret)
2339 return ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302340
Tomi Valkeinene4c5ae72015-04-10 12:48:39 +03002341 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",
2342 width, height,
2343 out_width, out_height,
2344 out_width / width, DIV_FRAC(out_width, width),
2345 out_height / height, DIV_FRAC(out_height, height),
2346
2347 decim_x, decim_y,
2348 width / decim_x, height / decim_y,
2349 out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
2350 out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
2351
2352 *five_taps ? 5 : 3,
2353 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302354
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302355 if (!core_clk || core_clk > dispc_core_clk_rate()) {
Archit Taneja79ad75f2011-09-08 13:15:11 +05302356 DSSERR("failed to set up scaling, "
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302357 "required core clk rate = %lu Hz, "
2358 "current core clk rate = %lu Hz\n",
2359 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302360 return -EINVAL;
2361 }
2362
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302363 *x_predecim = decim_x;
2364 *y_predecim = decim_y;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302365 return 0;
2366}
2367
Jyri Sarha864050c2017-03-24 16:47:52 +02002368static int dispc_ovl_setup_common(enum omap_plane_id plane,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302369 enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
2370 u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002371 u16 out_width, u16 out_height, u32 fourcc,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302372 u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha,
2373 u8 global_alpha, enum omap_dss_rotation_type rotation_type,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002374 bool replication, const struct videomode *vm,
Archit Taneja8ba85302012-09-26 17:00:37 +05302375 bool mem_to_mem)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002376{
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302377 bool five_taps = true;
Peter Senna Tschudin62a83182013-09-22 20:44:11 +02002378 bool fieldmode = false;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302379 int r, cconv = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002380 unsigned offset0, offset1;
2381 s32 row_inc;
2382 s32 pix_inc;
Archit Taneja6be0d732012-11-07 11:45:04 +05302383 u16 frame_width, frame_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002384 unsigned int field_offset = 0;
Archit Taneja84a880f2012-09-26 16:57:37 +05302385 u16 in_height = height;
2386 u16 in_width = width;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302387 int x_predecim = 1, y_predecim = 1;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002388 bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED);
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002389 unsigned long pclk = dispc_plane_pclk_rate(plane);
2390 unsigned long lclk = dispc_plane_lclk_rate(plane);
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02002391
Tomi Valkeinene5666582014-11-28 14:34:15 +02002392 if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002393 return -EINVAL;
2394
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002395 if (format_is_yuv(fourcc) && (in_width & 1)) {
Tomi Valkeinen5edec142017-05-04 09:13:32 +03002396 DSSERR("input width %d is not even for YUV format\n", in_width);
2397 return -EINVAL;
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002398 }
2399
Archit Taneja84a880f2012-09-26 16:57:37 +05302400 out_width = out_width == 0 ? width : out_width;
2401 out_height = out_height == 0 ? height : out_height;
Tomi Valkeinencf073662011-11-03 16:08:27 +02002402
Archit Taneja84a880f2012-09-26 16:57:37 +05302403 if (ilace && height == out_height)
Peter Senna Tschudin62a83182013-09-22 20:44:11 +02002404 fieldmode = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002405
2406 if (ilace) {
2407 if (fieldmode)
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302408 in_height /= 2;
Archit Taneja8eeb7012012-08-22 12:33:49 +05302409 pos_y /= 2;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302410 out_height /= 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002411
2412 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
Archit Taneja84a880f2012-09-26 16:57:37 +05302413 "out_height %d\n", in_height, pos_y,
2414 out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002415 }
2416
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002417 if (!dss_feat_color_mode_supported(plane, fourcc))
Archit Taneja8dad2ab2010-11-25 17:58:10 +05302418 return -EINVAL;
2419
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002420 r = dispc_ovl_calc_scaling(pclk, lclk, caps, vm, in_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002421 in_height, out_width, out_height, fourcc,
Archit Taneja84a880f2012-09-26 16:57:37 +05302422 &five_taps, &x_predecim, &y_predecim, pos_x,
Archit Taneja8ba85302012-09-26 17:00:37 +05302423 rotation_type, mem_to_mem);
Archit Taneja79ad75f2011-09-08 13:15:11 +05302424 if (r)
2425 return r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002426
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002427 in_width = in_width / x_predecim;
2428 in_height = in_height / y_predecim;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302429
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002430 if (x_predecim > 1 || y_predecim > 1)
2431 DSSDBG("predecimation %d x %x, new input size %d x %d\n",
2432 x_predecim, y_predecim, in_width, in_height);
2433
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002434 if (format_is_yuv(fourcc) && (in_width & 1)) {
Tomi Valkeinen5edec142017-05-04 09:13:32 +03002435 DSSDBG("predecimated input width is not even for YUV format\n");
2436 DSSDBG("adjusting input width %d -> %d\n",
2437 in_width, in_width & ~1);
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002438
Tomi Valkeinen5edec142017-05-04 09:13:32 +03002439 in_width &= ~1;
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002440 }
2441
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002442 if (format_is_yuv(fourcc))
Archit Taneja79ad75f2011-09-08 13:15:11 +05302443 cconv = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002444
2445 if (ilace && !fieldmode) {
2446 /*
2447 * when downscaling the bottom field may have to start several
2448 * source lines below the top field. Unfortunately ACCUI
2449 * registers will only hold the fractional part of the offset
2450 * so the integer part must be added to the base address of the
2451 * bottom field.
2452 */
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302453 if (!in_height || in_height == out_height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002454 field_offset = 0;
2455 else
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302456 field_offset = in_height / out_height / 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002457 }
2458
2459 /* Fields are independent but interleaved in memory. */
2460 if (fieldmode)
2461 field_offset = 1;
2462
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002463 offset0 = 0;
2464 offset1 = 0;
2465 row_inc = 0;
2466 pix_inc = 0;
2467
Archit Taneja6be0d732012-11-07 11:45:04 +05302468 if (plane == OMAP_DSS_WB) {
2469 frame_width = out_width;
2470 frame_height = out_height;
2471 } else {
2472 frame_width = in_width;
2473 frame_height = height;
2474 }
2475
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03002476 calc_offset(screen_width, frame_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002477 fourcc, fieldmode, field_offset,
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03002478 &offset0, &offset1, &row_inc, &pix_inc,
2479 x_predecim, y_predecim);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002480
2481 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2482 offset0, offset1, row_inc, pix_inc);
2483
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002484 dispc_ovl_set_color_mode(plane, fourcc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002485
Archit Taneja84a880f2012-09-26 16:57:37 +05302486 dispc_ovl_configure_burst_type(plane, rotation_type);
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302487
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02002488 if (dispc.feat->reverse_ilace_field_order)
2489 swap(offset0, offset1);
2490
Archit Taneja84a880f2012-09-26 16:57:37 +05302491 dispc_ovl_set_ba0(plane, paddr + offset0);
2492 dispc_ovl_set_ba1(plane, paddr + offset1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002493
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002494 if (fourcc == DRM_FORMAT_NV12) {
Archit Taneja84a880f2012-09-26 16:57:37 +05302495 dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
2496 dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
Amber Jain0d66cbb2011-05-19 19:47:54 +05302497 }
2498
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03002499 if (dispc.feat->last_pixel_inc_missing)
2500 row_inc += pix_inc - 1;
2501
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002502 dispc_ovl_set_row_inc(plane, row_inc);
2503 dispc_ovl_set_pix_inc(plane, pix_inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002504
Archit Taneja84a880f2012-09-26 16:57:37 +05302505 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302506 in_height, out_width, out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002507
Archit Taneja84a880f2012-09-26 16:57:37 +05302508 dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002509
Archit Taneja78b687f2012-09-21 14:51:49 +05302510 dispc_ovl_set_input_size(plane, in_width, in_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002511
Archit Taneja5b54ed32012-09-26 16:55:27 +05302512 if (caps & OMAP_DSS_OVL_CAP_SCALE) {
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302513 dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2514 out_height, ilace, five_taps, fieldmode,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002515 fourcc, rotation);
Archit Taneja78b687f2012-09-21 14:51:49 +05302516 dispc_ovl_set_output_size(plane, out_width, out_height);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002517 dispc_ovl_set_vid_color_conv(plane, cconv);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002518 }
2519
Archit Tanejac35eeb22013-03-26 19:15:24 +05302520 dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, mirror,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002521 fourcc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002522
Archit Taneja84a880f2012-09-26 16:57:37 +05302523 dispc_ovl_set_zorder(plane, caps, zorder);
2524 dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
2525 dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002526
Archit Tanejad79db852012-09-22 12:30:17 +05302527 dispc_ovl_enable_replication(plane, caps, replication);
Archit Tanejac3d925292011-09-14 11:52:54 +05302528
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002529 return 0;
2530}
2531
Jyri Sarha864050c2017-03-24 16:47:52 +02002532static int dispc_ovl_setup(enum omap_plane_id plane,
Jyri Sarha273ffea2017-03-24 16:47:53 +02002533 const struct omap_overlay_info *oi,
Tomi Valkeinen49a30572017-02-17 12:30:07 +02002534 const struct videomode *vm, bool mem_to_mem,
2535 enum omap_channel channel)
Archit Taneja84a880f2012-09-26 16:57:37 +05302536{
2537 int r;
Tomi Valkeinen16bf20c2012-10-15 15:33:22 +03002538 enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane);
Tomi Valkeinenbe2d68c2016-08-29 13:15:02 +03002539 const bool replication = true;
Archit Taneja84a880f2012-09-26 16:57:37 +05302540
Arnd Bergmann24f13a62014-04-24 13:28:18 +01002541 DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
2542 " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
2543 plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
Archit Taneja84a880f2012-09-26 16:57:37 +05302544 oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002545 oi->fourcc, oi->rotation, oi->mirror, channel, replication);
Archit Taneja84a880f2012-09-26 16:57:37 +05302546
Tomi Valkeinen49a30572017-02-17 12:30:07 +02002547 dispc_ovl_set_channel_out(plane, channel);
2548
Tomi Valkeinen16bf20c2012-10-15 15:33:22 +03002549 r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302550 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002551 oi->out_width, oi->out_height, oi->fourcc, oi->rotation,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302552 oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002553 oi->rotation_type, replication, vm, mem_to_mem);
Archit Taneja84a880f2012-09-26 16:57:37 +05302554
2555 return r;
2556}
2557
Archit Taneja749feff2012-08-31 12:32:52 +05302558int dispc_wb_setup(const struct omap_dss_writeback_info *wi,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002559 bool mem_to_mem, const struct videomode *vm)
Archit Taneja749feff2012-08-31 12:32:52 +05302560{
2561 int r;
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302562 u32 l;
Jyri Sarha864050c2017-03-24 16:47:52 +02002563 enum omap_plane_id plane = OMAP_DSS_WB;
Archit Taneja749feff2012-08-31 12:32:52 +05302564 const int pos_x = 0, pos_y = 0;
2565 const u8 zorder = 0, global_alpha = 0;
Tomi Valkeinenbe2d68c2016-08-29 13:15:02 +03002566 const bool replication = true;
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302567 bool truncation;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002568 int in_width = vm->hactive;
2569 int in_height = vm->vactive;
Archit Taneja749feff2012-08-31 12:32:52 +05302570 enum omap_overlay_caps caps =
2571 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
2572
2573 DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
2574 "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002575 in_height, wi->width, wi->height, wi->fourcc, wi->rotation,
Archit Taneja749feff2012-08-31 12:32:52 +05302576 wi->mirror);
2577
2578 r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
2579 wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002580 wi->height, wi->fourcc, wi->rotation, wi->mirror, zorder,
Archit Taneja749feff2012-08-31 12:32:52 +05302581 wi->pre_mult_alpha, global_alpha, wi->rotation_type,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002582 replication, vm, mem_to_mem);
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302583
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002584 switch (wi->fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03002585 case DRM_FORMAT_RGB565:
2586 case DRM_FORMAT_RGB888:
2587 case DRM_FORMAT_ARGB4444:
2588 case DRM_FORMAT_RGBA4444:
2589 case DRM_FORMAT_RGBX4444:
2590 case DRM_FORMAT_ARGB1555:
2591 case DRM_FORMAT_XRGB1555:
2592 case DRM_FORMAT_XRGB4444:
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302593 truncation = true;
2594 break;
2595 default:
2596 truncation = false;
2597 break;
2598 }
2599
2600 /* setup extra DISPC_WB_ATTRIBUTES */
2601 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
2602 l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
2603 l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
Tomi Valkeinen4c055ce2015-11-04 17:10:53 +02002604 if (mem_to_mem)
2605 l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002606 else
2607 l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302608 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Archit Taneja749feff2012-08-31 12:32:52 +05302609
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002610 if (mem_to_mem) {
2611 /* WBDELAYCOUNT */
2612 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
2613 } else {
2614 int wbdelay;
2615
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002616 wbdelay = min(vm->vfront_porch +
2617 vm->vsync_len + vm->vback_porch, (u32)255);
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002618
2619 /* WBDELAYCOUNT */
2620 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
2621 }
2622
Archit Taneja749feff2012-08-31 12:32:52 +05302623 return r;
2624}
2625
Jyri Sarha864050c2017-03-24 16:47:52 +02002626static int dispc_ovl_enable(enum omap_plane_id plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002627{
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002628 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2629
Archit Taneja9b372c22011-05-06 11:45:49 +05302630 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002631
2632 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002633}
2634
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02002635static enum omap_dss_output_id dispc_mgr_get_supported_outputs(enum omap_channel channel)
Tomi Valkeinen7b9cb5e2015-11-04 15:11:25 +02002636{
2637 return dss_feat_get_supported_outputs(channel);
2638}
Tomi Valkeinen7b9cb5e2015-11-04 15:11:25 +02002639
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002640static void dispc_lcd_enable_signal_polarity(bool act_high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002641{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002642 if (!dss_has_feature(FEAT_LCDENABLEPOL))
2643 return;
2644
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002645 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002646}
2647
2648void dispc_lcd_enable_signal(bool enable)
2649{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002650 if (!dss_has_feature(FEAT_LCDENABLESIGNAL))
2651 return;
2652
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002653 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002654}
2655
2656void dispc_pck_free_enable(bool enable)
2657{
Archit Taneja6ced40b2010-12-02 11:27:13 +00002658 if (!dss_has_feature(FEAT_PCKFREEENABLE))
2659 return;
2660
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002661 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002662}
2663
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02002664static int dispc_get_num_mgrs(void)
Tomi Valkeinenc2834002015-11-05 19:54:33 +02002665{
2666 return dss_feat_get_num_mgrs();
2667}
Tomi Valkeinenc2834002015-11-05 19:54:33 +02002668
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002669static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002670{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302671 mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002672}
2673
2674
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002675static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002676{
Archit Tanejad21f43b2012-06-21 09:45:11 +05302677 mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002678}
2679
Tomi Valkeinen65904152015-11-04 17:10:57 +02002680static void dispc_set_loadmode(enum omap_dss_load_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002681{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002682 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002683}
2684
2685
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002686static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002687{
Sumit Semwal8613b002010-12-02 11:27:09 +00002688 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002689}
2690
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002691static void dispc_mgr_set_trans_key(enum omap_channel ch,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002692 enum omap_dss_trans_key_type type,
2693 u32 trans_key)
2694{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302695 mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002696
Sumit Semwal8613b002010-12-02 11:27:09 +00002697 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002698}
2699
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002700static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002701{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302702 mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002703}
Archit Taneja11354dd2011-09-26 11:47:29 +05302704
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002705static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2706 bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002707{
Archit Taneja11354dd2011-09-26 11:47:29 +05302708 if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002709 return;
2710
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002711 if (ch == OMAP_DSS_CHANNEL_LCD)
2712 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
Sumit Semwal2a205f32010-12-02 11:27:12 +00002713 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002714 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002715}
Archit Taneja11354dd2011-09-26 11:47:29 +05302716
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02002717static void dispc_mgr_setup(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02002718 const struct omap_overlay_manager_info *info)
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002719{
2720 dispc_mgr_set_default_color(channel, info->default_color);
2721 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
2722 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
2723 dispc_mgr_enable_alpha_fixed_zorder(channel,
2724 info->partial_alpha_enabled);
2725 if (dss_has_feature(FEAT_CPR)) {
2726 dispc_mgr_enable_cpr(channel, info->cpr_enable);
2727 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
2728 }
2729}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002730
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002731static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002732{
2733 int code;
2734
2735 switch (data_lines) {
2736 case 12:
2737 code = 0;
2738 break;
2739 case 16:
2740 code = 1;
2741 break;
2742 case 18:
2743 code = 2;
2744 break;
2745 case 24:
2746 code = 3;
2747 break;
2748 default:
2749 BUG();
2750 return;
2751 }
2752
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302753 mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002754}
2755
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002756static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002757{
2758 u32 l;
Archit Taneja569969d2011-08-22 17:41:57 +05302759 int gpout0, gpout1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002760
2761 switch (mode) {
Archit Taneja569969d2011-08-22 17:41:57 +05302762 case DSS_IO_PAD_MODE_RESET:
2763 gpout0 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002764 gpout1 = 0;
2765 break;
Archit Taneja569969d2011-08-22 17:41:57 +05302766 case DSS_IO_PAD_MODE_RFBI:
2767 gpout0 = 1;
2768 gpout1 = 0;
2769 break;
2770 case DSS_IO_PAD_MODE_BYPASS:
2771 gpout0 = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002772 gpout1 = 1;
2773 break;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002774 default:
2775 BUG();
2776 return;
2777 }
2778
Archit Taneja569969d2011-08-22 17:41:57 +05302779 l = dispc_read_reg(DISPC_CONTROL);
2780 l = FLD_MOD(l, gpout0, 15, 15);
2781 l = FLD_MOD(l, gpout1, 16, 16);
2782 dispc_write_reg(DISPC_CONTROL, l);
2783}
2784
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002785static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
Archit Taneja569969d2011-08-22 17:41:57 +05302786{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302787 mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002788}
2789
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02002790static void dispc_mgr_set_lcd_config(enum omap_channel channel,
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002791 const struct dss_lcd_mgr_config *config)
2792{
2793 dispc_mgr_set_io_pad_mode(config->io_pad_mode);
2794
2795 dispc_mgr_enable_stallmode(channel, config->stallmode);
2796 dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck);
2797
2798 dispc_mgr_set_clock_div(channel, &config->clock_info);
2799
2800 dispc_mgr_set_tft_data_lines(channel, config->video_port_width);
2801
2802 dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity);
2803
2804 dispc_mgr_set_lcd_type_tft(channel);
2805}
2806
Archit Taneja8f366162012-04-16 12:53:44 +05302807static bool _dispc_mgr_size_ok(u16 width, u16 height)
2808{
Archit Taneja33b89922012-11-14 13:50:15 +05302809 return width <= dispc.feat->mgr_width_max &&
2810 height <= dispc.feat->mgr_height_max;
Archit Taneja8f366162012-04-16 12:53:44 +05302811}
2812
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03002813static bool _dispc_lcd_timings_ok(int hsync_len, int hfp, int hbp,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002814 int vsw, int vfp, int vbp)
2815{
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03002816 if (hsync_len < 1 || hsync_len > dispc.feat->sw_max ||
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302817 hfp < 1 || hfp > dispc.feat->hp_max ||
2818 hbp < 1 || hbp > dispc.feat->hp_max ||
2819 vsw < 1 || vsw > dispc.feat->sw_max ||
2820 vfp < 0 || vfp > dispc.feat->vp_max ||
2821 vbp < 0 || vbp > dispc.feat->vp_max)
2822 return false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002823 return true;
2824}
2825
Archit Tanejaca5ca692013-03-26 19:15:22 +05302826static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
2827 unsigned long pclk)
2828{
2829 if (dss_mgr_is_lcd(channel))
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05002830 return pclk <= dispc.feat->max_lcd_pclk;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302831 else
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05002832 return pclk <= dispc.feat->max_tv_pclk;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302833}
2834
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002835bool dispc_mgr_timings_ok(enum omap_channel channel, const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002836{
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002837 if (!_dispc_mgr_size_ok(vm->hactive, vm->vactive))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002838 return false;
Archit Taneja8f366162012-04-16 12:53:44 +05302839
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002840 if (!_dispc_mgr_pclk_ok(channel, vm->pixelclock))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002841 return false;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302842
2843 if (dss_mgr_is_lcd(channel)) {
Tomi Valkeinenbeb83842014-06-05 11:35:10 +03002844 /* TODO: OMAP4+ supports interlace for LCD outputs */
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002845 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002846 return false;
Tomi Valkeinenbeb83842014-06-05 11:35:10 +03002847
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002848 if (!_dispc_lcd_timings_ok(vm->hsync_len,
2849 vm->hfront_porch, vm->hback_porch,
2850 vm->vsync_len, vm->vfront_porch,
2851 vm->vback_porch))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002852 return false;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302853 }
Archit Taneja8f366162012-04-16 12:53:44 +05302854
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002855 return true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002856}
2857
Peter Ujfalusi3b592932016-09-22 14:06:56 +03002858static void _dispc_mgr_set_lcd_timings(enum omap_channel channel,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002859 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002860{
Archit Taneja655e2942012-06-21 10:37:43 +05302861 u32 timing_h, timing_v, l;
Tomi Valkeinened351882014-10-02 17:58:49 +00002862 bool onoff, rf, ipc, vs, hs, de;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002863
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002864 timing_h = FLD_VAL(vm->hsync_len - 1, dispc.feat->sw_start, 0) |
2865 FLD_VAL(vm->hfront_porch - 1, dispc.feat->fp_start, 8) |
2866 FLD_VAL(vm->hback_porch - 1, dispc.feat->bp_start, 20);
2867 timing_v = FLD_VAL(vm->vsync_len - 1, dispc.feat->sw_start, 0) |
2868 FLD_VAL(vm->vfront_porch, dispc.feat->fp_start, 8) |
2869 FLD_VAL(vm->vback_porch, dispc.feat->bp_start, 20);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002870
Sumit Semwal64ba4f72010-12-02 11:27:10 +00002871 dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
2872 dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
Archit Taneja655e2942012-06-21 10:37:43 +05302873
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002874 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00002875 vs = false;
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03002876 else
2877 vs = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00002878
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002879 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00002880 hs = false;
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03002881 else
2882 hs = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00002883
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002884 if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00002885 de = false;
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +03002886 else
2887 de = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00002888
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002889 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
Archit Taneja655e2942012-06-21 10:37:43 +05302890 ipc = false;
Peter Ujfalusif149e172016-09-22 14:07:00 +03002891 else
Archit Taneja655e2942012-06-21 10:37:43 +05302892 ipc = true;
Archit Taneja655e2942012-06-21 10:37:43 +05302893
Tomi Valkeinen7a163602014-10-02 17:58:48 +00002894 /* always use the 'rf' setting */
2895 onoff = true;
2896
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002897 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
Archit Taneja655e2942012-06-21 10:37:43 +05302898 rf = true;
Peter Ujfalusid34afb72016-09-22 14:07:01 +03002899 else
2900 rf = false;
Archit Taneja655e2942012-06-21 10:37:43 +05302901
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03002902 l = FLD_VAL(onoff, 17, 17) |
2903 FLD_VAL(rf, 16, 16) |
Tomi Valkeinened351882014-10-02 17:58:49 +00002904 FLD_VAL(de, 15, 15) |
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03002905 FLD_VAL(ipc, 14, 14) |
Tomi Valkeinened351882014-10-02 17:58:49 +00002906 FLD_VAL(hs, 13, 13) |
2907 FLD_VAL(vs, 12, 12);
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03002908
Tomi Valkeinene5f80912015-10-21 13:08:59 +03002909 /* always set ALIGN bit when available */
2910 if (dispc.feat->supports_sync_align)
2911 l |= (1 << 18);
2912
Archit Taneja655e2942012-06-21 10:37:43 +05302913 dispc_write_reg(DISPC_POL_FREQ(channel), l);
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00002914
2915 if (dispc.syscon_pol) {
2916 const int shifts[] = {
2917 [OMAP_DSS_CHANNEL_LCD] = 0,
2918 [OMAP_DSS_CHANNEL_LCD2] = 1,
2919 [OMAP_DSS_CHANNEL_LCD3] = 2,
2920 };
2921
2922 u32 mask, val;
2923
2924 mask = (1 << 0) | (1 << 3) | (1 << 6);
2925 val = (rf << 0) | (ipc << 3) | (onoff << 6);
2926
2927 mask <<= 16 + shifts[channel];
2928 val <<= 16 + shifts[channel];
2929
2930 regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
2931 mask, val);
2932 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002933}
2934
Tomi Valkeinen956d4f92016-11-23 13:23:42 +02002935static int vm_flag_to_int(enum display_flags flags, enum display_flags high,
2936 enum display_flags low)
2937{
2938 if (flags & high)
2939 return 1;
2940 if (flags & low)
2941 return -1;
2942 return 0;
2943}
2944
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002945/* change name to mode? */
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02002946static void dispc_mgr_set_timings(enum omap_channel channel,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002947 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002948{
2949 unsigned xtot, ytot;
2950 unsigned long ht, vt;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002951 struct videomode t = *vm;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002952
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03002953 DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
Archit Tanejac51d9212012-04-16 12:53:43 +05302954
Archit Taneja2aefad42012-05-18 14:36:54 +05302955 if (!dispc_mgr_timings_ok(channel, &t)) {
Archit Taneja8f366162012-04-16 12:53:44 +05302956 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002957 return;
2958 }
Archit Tanejac51d9212012-04-16 12:53:43 +05302959
Archit Tanejadd88b7a2012-06-29 14:41:30 +05302960 if (dss_mgr_is_lcd(channel)) {
Peter Ujfalusi3b592932016-09-22 14:06:56 +03002961 _dispc_mgr_set_lcd_timings(channel, &t);
Archit Tanejac51d9212012-04-16 12:53:43 +05302962
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03002963 xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch;
Peter Ujfalusi458540c2016-09-22 14:06:53 +03002964 ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch;
Archit Tanejac51d9212012-04-16 12:53:43 +05302965
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002966 ht = vm->pixelclock / xtot;
2967 vt = vm->pixelclock / xtot / ytot;
Archit Tanejac51d9212012-04-16 12:53:43 +05302968
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002969 DSSDBG("pck %lu\n", vm->pixelclock);
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03002970 DSSDBG("hsync_len %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03002971 t.hsync_len, t.hfront_porch, t.hback_porch,
Peter Ujfalusi458540c2016-09-22 14:06:53 +03002972 t.vsync_len, t.vfront_porch, t.vback_porch);
Archit Taneja655e2942012-06-21 10:37:43 +05302973 DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n",
Tomi Valkeinen956d4f92016-11-23 13:23:42 +02002974 vm_flag_to_int(t.flags, DISPLAY_FLAGS_VSYNC_HIGH, DISPLAY_FLAGS_VSYNC_LOW),
2975 vm_flag_to_int(t.flags, DISPLAY_FLAGS_HSYNC_HIGH, DISPLAY_FLAGS_HSYNC_LOW),
2976 vm_flag_to_int(t.flags, DISPLAY_FLAGS_PIXDATA_POSEDGE, DISPLAY_FLAGS_PIXDATA_NEGEDGE),
2977 vm_flag_to_int(t.flags, DISPLAY_FLAGS_DE_HIGH, DISPLAY_FLAGS_DE_LOW),
2978 vm_flag_to_int(t.flags, DISPLAY_FLAGS_SYNC_POSEDGE, DISPLAY_FLAGS_SYNC_NEGEDGE));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002979
Archit Tanejac51d9212012-04-16 12:53:43 +05302980 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
Archit Taneja2aefad42012-05-18 14:36:54 +05302981 } else {
Peter Ujfalusi53058292016-09-22 14:06:55 +03002982 if (t.flags & DISPLAY_FLAGS_INTERLACED)
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03002983 t.vactive /= 2;
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02002984
2985 if (dispc.feat->supports_double_pixel)
Peter Ujfalusi531efb32016-09-22 14:06:59 +03002986 REG_FLD_MOD(DISPC_CONTROL,
2987 !!(t.flags & DISPLAY_FLAGS_DOUBLECLK),
2988 19, 17);
Archit Tanejac51d9212012-04-16 12:53:43 +05302989 }
Archit Taneja8f366162012-04-16 12:53:44 +05302990
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03002991 dispc_mgr_set_size(channel, t.hactive, t.vactive);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002992}
2993
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03002994static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00002995 u16 pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002996{
2997 BUG_ON(lck_div < 1);
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03002998 BUG_ON(pck_div < 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002999
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003000 dispc_write_reg(DISPC_DIVISORo(channel),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003001 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003002
Luis de Bethencourt0bcfdba2015-10-15 13:29:38 +01003003 if (!dss_has_feature(FEAT_CORE_CLK_DIV) &&
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003004 channel == OMAP_DSS_CHANNEL_LCD)
3005 dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003006}
3007
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003008static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
Sumit Semwal2a205f32010-12-02 11:27:12 +00003009 int *pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003010{
3011 u32 l;
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003012 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003013 *lck_div = FLD_GET(l, 23, 16);
3014 *pck_div = FLD_GET(l, 7, 0);
3015}
3016
Tomi Valkeinen65904152015-11-04 17:10:57 +02003017static unsigned long dispc_fclk_rate(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003018{
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003019 unsigned long r;
3020 enum dss_clk_source src;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003021
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003022 src = dss_get_dispc_clk_source();
3023
3024 if (src == DSS_CLK_SRC_FCK) {
Tomi Valkeinen5aaee692012-12-12 10:37:03 +02003025 r = dss_get_dispc_clk_rate();
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003026 } else {
3027 struct dss_pll *pll;
3028 unsigned clkout_idx;
Tomi Valkeinen93550922014-12-31 11:25:48 +02003029
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003030 pll = dss_pll_find_by_src(src);
3031 clkout_idx = dss_pll_get_clkout_idx_for_src(src);
Tomi Valkeinen93550922014-12-31 11:25:48 +02003032
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003033 r = pll->cinfo.clkout[clkout_idx];
Taneja, Archit66534e82011-03-08 05:50:34 -06003034 }
3035
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003036 return r;
3037}
3038
Tomi Valkeinen65904152015-11-04 17:10:57 +02003039static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003040{
3041 int lcd;
3042 unsigned long r;
Tomi Valkeinen01575772016-05-17 16:08:34 +03003043 enum dss_clk_source src;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003044
Tomi Valkeinen01575772016-05-17 16:08:34 +03003045 /* for TV, LCLK rate is the FCLK rate */
3046 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003047 return dispc_fclk_rate();
Tomi Valkeinen01575772016-05-17 16:08:34 +03003048
3049 src = dss_get_lcd_clk_source(channel);
3050
3051 if (src == DSS_CLK_SRC_FCK) {
3052 r = dss_get_dispc_clk_rate();
3053 } else {
3054 struct dss_pll *pll;
3055 unsigned clkout_idx;
3056
3057 pll = dss_pll_find_by_src(src);
3058 clkout_idx = dss_pll_get_clkout_idx_for_src(src);
3059
3060 r = pll->cinfo.clkout[clkout_idx];
Taneja, Architea751592011-03-08 05:50:35 -06003061 }
Tomi Valkeinen01575772016-05-17 16:08:34 +03003062
3063 lcd = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3064
3065 return r / lcd;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003066}
3067
Tomi Valkeinen65904152015-11-04 17:10:57 +02003068static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003069{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003070 unsigned long r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003071
Archit Tanejadd88b7a2012-06-29 14:41:30 +05303072 if (dss_mgr_is_lcd(channel)) {
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303073 int pcd;
3074 u32 l;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003075
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303076 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003077
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303078 pcd = FLD_GET(l, 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003079
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303080 r = dispc_mgr_lclk_rate(channel);
3081
3082 return r / pcd;
3083 } else {
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003084 return dispc.tv_pclk_rate;
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303085 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003086}
3087
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003088void dispc_set_tv_pclk(unsigned long pclk)
3089{
3090 dispc.tv_pclk_rate = pclk;
3091}
3092
Tomi Valkeinen65904152015-11-04 17:10:57 +02003093static unsigned long dispc_core_clk_rate(void)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05303094{
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003095 return dispc.core_clk_rate;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05303096}
3097
Jyri Sarha864050c2017-03-24 16:47:52 +02003098static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane)
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303099{
Tomi Valkeinen251886d2012-11-15 13:20:02 +02003100 enum omap_channel channel;
3101
3102 if (plane == OMAP_DSS_WB)
3103 return 0;
3104
3105 channel = dispc_ovl_get_channel_out(plane);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303106
3107 return dispc_mgr_pclk_rate(channel);
3108}
3109
Jyri Sarha864050c2017-03-24 16:47:52 +02003110static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane)
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303111{
Tomi Valkeinen251886d2012-11-15 13:20:02 +02003112 enum omap_channel channel;
3113
3114 if (plane == OMAP_DSS_WB)
3115 return 0;
3116
3117 channel = dispc_ovl_get_channel_out(plane);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303118
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003119 return dispc_mgr_lclk_rate(channel);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303120}
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003121
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303122static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003123{
3124 int lcd, pcd;
Tomi Valkeinendc0352d2016-05-17 13:45:09 +03003125 enum dss_clk_source lcd_clk_src;
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303126
3127 seq_printf(s, "- %s -\n", mgr_desc[channel].name);
3128
3129 lcd_clk_src = dss_get_lcd_clk_source(channel);
3130
Tomi Valkeinen557a1542016-05-17 13:49:18 +03003131 seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name,
Tomi Valkeinen407bd562016-05-17 13:50:55 +03003132 dss_get_clk_source_name(lcd_clk_src));
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303133
3134 dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
3135
3136 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3137 dispc_mgr_lclk_rate(channel), lcd);
3138 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
3139 dispc_mgr_pclk_rate(channel), pcd);
3140}
3141
3142void dispc_dump_clocks(struct seq_file *s)
3143{
3144 int lcd;
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003145 u32 l;
Tomi Valkeinendc0352d2016-05-17 13:45:09 +03003146 enum dss_clk_source dispc_clk_src = dss_get_dispc_clk_source();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003147
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003148 if (dispc_runtime_get())
3149 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003150
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003151 seq_printf(s, "- DISPC -\n");
3152
Tomi Valkeinen557a1542016-05-17 13:49:18 +03003153 seq_printf(s, "dispc fclk source = %s\n",
Tomi Valkeinen407bd562016-05-17 13:50:55 +03003154 dss_get_clk_source_name(dispc_clk_src));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003155
3156 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
Sumit Semwal2a205f32010-12-02 11:27:12 +00003157
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003158 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3159 seq_printf(s, "- DISPC-CORE-CLK -\n");
3160 l = dispc_read_reg(DISPC_DIVISOR);
3161 lcd = FLD_GET(l, 23, 16);
3162
3163 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3164 (dispc_fclk_rate()/lcd), lcd);
3165 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003166
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303167 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
Taneja, Architea751592011-03-08 05:50:35 -06003168
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303169 if (dss_has_feature(FEAT_MGR_LCD2))
3170 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
3171 if (dss_has_feature(FEAT_MGR_LCD3))
3172 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003173
3174 dispc_runtime_put();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003175}
3176
Tomi Valkeinene40402c2012-03-02 18:01:07 +02003177static void dispc_dump_regs(struct seq_file *s)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003178{
Archit Taneja4dd2da12011-08-05 19:06:01 +05303179 int i, j;
3180 const char *mgr_names[] = {
3181 [OMAP_DSS_CHANNEL_LCD] = "LCD",
3182 [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3183 [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303184 [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303185 };
3186 const char *ovl_names[] = {
3187 [OMAP_DSS_GFX] = "GFX",
3188 [OMAP_DSS_VIDEO1] = "VID1",
3189 [OMAP_DSS_VIDEO2] = "VID2",
Archit Tanejab8c095b2011-09-13 18:20:33 +05303190 [OMAP_DSS_VIDEO3] = "VID3",
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003191 [OMAP_DSS_WB] = "WB",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303192 };
3193 const char **p_names;
3194
Archit Taneja9b372c22011-05-06 11:45:49 +05303195#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003196
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003197 if (dispc_runtime_get())
3198 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003199
Archit Taneja5010be82011-08-05 19:06:00 +05303200 /* DISPC common registers */
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003201 DUMPREG(DISPC_REVISION);
3202 DUMPREG(DISPC_SYSCONFIG);
3203 DUMPREG(DISPC_SYSSTATUS);
3204 DUMPREG(DISPC_IRQSTATUS);
3205 DUMPREG(DISPC_IRQENABLE);
3206 DUMPREG(DISPC_CONTROL);
3207 DUMPREG(DISPC_CONFIG);
3208 DUMPREG(DISPC_CAPABLE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003209 DUMPREG(DISPC_LINE_STATUS);
3210 DUMPREG(DISPC_LINE_NUMBER);
Archit Taneja11354dd2011-09-26 11:47:29 +05303211 if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
3212 dss_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003213 DUMPREG(DISPC_GLOBAL_ALPHA);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003214 if (dss_has_feature(FEAT_MGR_LCD2)) {
3215 DUMPREG(DISPC_CONTROL2);
3216 DUMPREG(DISPC_CONFIG2);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003217 }
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303218 if (dss_has_feature(FEAT_MGR_LCD3)) {
3219 DUMPREG(DISPC_CONTROL3);
3220 DUMPREG(DISPC_CONFIG3);
3221 }
Tomi Valkeinen29fceee2013-11-14 11:38:25 +02003222 if (dss_has_feature(FEAT_MFLAG))
3223 DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003224
Archit Taneja5010be82011-08-05 19:06:00 +05303225#undef DUMPREG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003226
Archit Taneja5010be82011-08-05 19:06:00 +05303227#define DISPC_REG(i, name) name(i)
Archit Taneja4dd2da12011-08-05 19:06:01 +05303228#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
Tomi Valkeinen311d5ce2012-09-28 13:58:14 +03003229 (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303230 dispc_read_reg(DISPC_REG(i, r)))
3231
Archit Taneja4dd2da12011-08-05 19:06:01 +05303232 p_names = mgr_names;
Archit Taneja5010be82011-08-05 19:06:00 +05303233
Archit Taneja4dd2da12011-08-05 19:06:01 +05303234 /* DISPC channel specific registers */
3235 for (i = 0; i < dss_feat_get_num_mgrs(); i++) {
3236 DUMPREG(i, DISPC_DEFAULT_COLOR);
3237 DUMPREG(i, DISPC_TRANS_COLOR);
3238 DUMPREG(i, DISPC_SIZE_MGR);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003239
Archit Taneja4dd2da12011-08-05 19:06:01 +05303240 if (i == OMAP_DSS_CHANNEL_DIGIT)
3241 continue;
Archit Taneja5010be82011-08-05 19:06:00 +05303242
Archit Taneja4dd2da12011-08-05 19:06:01 +05303243 DUMPREG(i, DISPC_TIMING_H);
3244 DUMPREG(i, DISPC_TIMING_V);
3245 DUMPREG(i, DISPC_POL_FREQ);
3246 DUMPREG(i, DISPC_DIVISORo);
Archit Taneja5010be82011-08-05 19:06:00 +05303247
Archit Taneja4dd2da12011-08-05 19:06:01 +05303248 DUMPREG(i, DISPC_DATA_CYCLE1);
3249 DUMPREG(i, DISPC_DATA_CYCLE2);
3250 DUMPREG(i, DISPC_DATA_CYCLE3);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003251
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003252 if (dss_has_feature(FEAT_CPR)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303253 DUMPREG(i, DISPC_CPR_COEF_R);
3254 DUMPREG(i, DISPC_CPR_COEF_G);
3255 DUMPREG(i, DISPC_CPR_COEF_B);
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003256 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003257 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003258
Archit Taneja4dd2da12011-08-05 19:06:01 +05303259 p_names = ovl_names;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003260
Archit Taneja4dd2da12011-08-05 19:06:01 +05303261 for (i = 0; i < dss_feat_get_num_ovls(); i++) {
3262 DUMPREG(i, DISPC_OVL_BA0);
3263 DUMPREG(i, DISPC_OVL_BA1);
3264 DUMPREG(i, DISPC_OVL_POSITION);
3265 DUMPREG(i, DISPC_OVL_SIZE);
3266 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3267 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3268 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3269 DUMPREG(i, DISPC_OVL_ROW_INC);
3270 DUMPREG(i, DISPC_OVL_PIXEL_INC);
Tomi Valkeinenaba837a2014-09-29 20:46:16 +00003271
Archit Taneja4dd2da12011-08-05 19:06:01 +05303272 if (dss_has_feature(FEAT_PRELOAD))
3273 DUMPREG(i, DISPC_OVL_PRELOAD);
Tomi Valkeinenaba837a2014-09-29 20:46:16 +00003274 if (dss_has_feature(FEAT_MFLAG))
3275 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003276
Archit Taneja4dd2da12011-08-05 19:06:01 +05303277 if (i == OMAP_DSS_GFX) {
3278 DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
3279 DUMPREG(i, DISPC_OVL_TABLE_BA);
3280 continue;
3281 }
3282
3283 DUMPREG(i, DISPC_OVL_FIR);
3284 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3285 DUMPREG(i, DISPC_OVL_ACCU0);
3286 DUMPREG(i, DISPC_OVL_ACCU1);
3287 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3288 DUMPREG(i, DISPC_OVL_BA0_UV);
3289 DUMPREG(i, DISPC_OVL_BA1_UV);
3290 DUMPREG(i, DISPC_OVL_FIR2);
3291 DUMPREG(i, DISPC_OVL_ACCU2_0);
3292 DUMPREG(i, DISPC_OVL_ACCU2_1);
3293 }
3294 if (dss_has_feature(FEAT_ATTR2))
3295 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
Archit Taneja5010be82011-08-05 19:06:00 +05303296 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003297
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02003298 if (dispc.feat->has_writeback) {
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003299 i = OMAP_DSS_WB;
3300 DUMPREG(i, DISPC_OVL_BA0);
3301 DUMPREG(i, DISPC_OVL_BA1);
3302 DUMPREG(i, DISPC_OVL_SIZE);
3303 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3304 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3305 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3306 DUMPREG(i, DISPC_OVL_ROW_INC);
3307 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3308
3309 if (dss_has_feature(FEAT_MFLAG))
3310 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
3311
3312 DUMPREG(i, DISPC_OVL_FIR);
3313 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3314 DUMPREG(i, DISPC_OVL_ACCU0);
3315 DUMPREG(i, DISPC_OVL_ACCU1);
3316 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3317 DUMPREG(i, DISPC_OVL_BA0_UV);
3318 DUMPREG(i, DISPC_OVL_BA1_UV);
3319 DUMPREG(i, DISPC_OVL_FIR2);
3320 DUMPREG(i, DISPC_OVL_ACCU2_0);
3321 DUMPREG(i, DISPC_OVL_ACCU2_1);
3322 }
3323 if (dss_has_feature(FEAT_ATTR2))
3324 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3325 }
3326
Archit Taneja5010be82011-08-05 19:06:00 +05303327#undef DISPC_REG
3328#undef DUMPREG
3329
3330#define DISPC_REG(plane, name, i) name(plane, i)
3331#define DUMPREG(plane, name, i) \
Archit Taneja4dd2da12011-08-05 19:06:01 +05303332 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
Tomi Valkeinen311d5ce2012-09-28 13:58:14 +03003333 (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303334 dispc_read_reg(DISPC_REG(plane, name, i)))
3335
Archit Taneja4dd2da12011-08-05 19:06:01 +05303336 /* Video pipeline coefficient registers */
Archit Taneja5010be82011-08-05 19:06:00 +05303337
Archit Taneja4dd2da12011-08-05 19:06:01 +05303338 /* start from OMAP_DSS_VIDEO1 */
3339 for (i = 1; i < dss_feat_get_num_ovls(); i++) {
3340 for (j = 0; j < 8; j++)
3341 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303342
Archit Taneja4dd2da12011-08-05 19:06:01 +05303343 for (j = 0; j < 8; j++)
3344 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303345
Archit Taneja4dd2da12011-08-05 19:06:01 +05303346 for (j = 0; j < 5; j++)
3347 DUMPREG(i, DISPC_OVL_CONV_COEF, j);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003348
Archit Taneja4dd2da12011-08-05 19:06:01 +05303349 if (dss_has_feature(FEAT_FIR_COEF_V)) {
3350 for (j = 0; j < 8; j++)
3351 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
3352 }
Amber Jainab5ca072011-05-19 19:47:53 +05303353
Archit Taneja4dd2da12011-08-05 19:06:01 +05303354 if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
3355 for (j = 0; j < 8; j++)
3356 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303357
Archit Taneja4dd2da12011-08-05 19:06:01 +05303358 for (j = 0; j < 8; j++)
3359 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303360
Archit Taneja4dd2da12011-08-05 19:06:01 +05303361 for (j = 0; j < 8; j++)
3362 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
3363 }
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003364 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003365
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003366 dispc_runtime_put();
Archit Taneja5010be82011-08-05 19:06:00 +05303367
3368#undef DISPC_REG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003369#undef DUMPREG
3370}
3371
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003372/* calculate clock rates using dividers in cinfo */
3373int dispc_calc_clock_rates(unsigned long dispc_fclk_rate,
3374 struct dispc_clock_info *cinfo)
3375{
3376 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3377 return -EINVAL;
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003378 if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003379 return -EINVAL;
3380
3381 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3382 cinfo->pck = cinfo->lck / cinfo->pck_div;
3383
3384 return 0;
3385}
3386
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003387bool dispc_div_calc(unsigned long dispc,
3388 unsigned long pck_min, unsigned long pck_max,
3389 dispc_div_calc_func func, void *data)
3390{
3391 int lckd, lckd_start, lckd_stop;
3392 int pckd, pckd_start, pckd_stop;
3393 unsigned long pck, lck;
3394 unsigned long lck_max;
3395 unsigned long pckd_hw_min, pckd_hw_max;
3396 unsigned min_fck_per_pck;
3397 unsigned long fck;
3398
3399#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
3400 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
3401#else
3402 min_fck_per_pck = 0;
3403#endif
3404
3405 pckd_hw_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD);
3406 pckd_hw_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD);
3407
3408 lck_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
3409
3410 pck_min = pck_min ? pck_min : 1;
3411 pck_max = pck_max ? pck_max : ULONG_MAX;
3412
3413 lckd_start = max(DIV_ROUND_UP(dispc, lck_max), 1ul);
3414 lckd_stop = min(dispc / pck_min, 255ul);
3415
3416 for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
3417 lck = dispc / lckd;
3418
3419 pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
3420 pckd_stop = min(lck / pck_min, pckd_hw_max);
3421
3422 for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
3423 pck = lck / pckd;
3424
3425 /*
3426 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
3427 * clock, which means we're configuring DISPC fclk here
3428 * also. Thus we need to use the calculated lck. For
3429 * OMAP4+ the DISPC fclk is a separate clock.
3430 */
3431 if (dss_has_feature(FEAT_CORE_CLK_DIV))
3432 fck = dispc_core_clk_rate();
3433 else
3434 fck = lck;
3435
3436 if (fck < pck * min_fck_per_pck)
3437 continue;
3438
3439 if (func(lckd, pckd, lck, pck, data))
3440 return true;
3441 }
3442 }
3443
3444 return false;
3445}
3446
Archit Tanejaf0d08f82012-06-29 14:00:54 +05303447void dispc_mgr_set_clock_div(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02003448 const struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003449{
3450 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3451 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3452
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003453 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003454}
3455
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003456int dispc_mgr_get_clock_div(enum omap_channel channel,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00003457 struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003458{
3459 unsigned long fck;
3460
3461 fck = dispc_fclk_rate();
3462
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003463 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3464 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003465
3466 cinfo->lck = fck / cinfo->lck_div;
3467 cinfo->pck = cinfo->lck / cinfo->pck_div;
3468
3469 return 0;
3470}
3471
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003472static u32 dispc_read_irqstatus(void)
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003473{
3474 return dispc_read_reg(DISPC_IRQSTATUS);
3475}
3476
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003477static void dispc_clear_irqstatus(u32 mask)
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003478{
3479 dispc_write_reg(DISPC_IRQSTATUS, mask);
3480}
3481
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003482static void dispc_write_irqenable(u32 mask)
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003483{
3484 u32 old_mask = dispc_read_reg(DISPC_IRQENABLE);
3485
3486 /* clear the irqstatus for newly enabled irqs */
3487 dispc_clear_irqstatus((mask ^ old_mask) & mask);
3488
3489 dispc_write_reg(DISPC_IRQENABLE, mask);
Tomi Valkeinen2e953d82017-02-20 13:18:38 +02003490
3491 /* flush posted write */
3492 dispc_read_reg(DISPC_IRQENABLE);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003493}
3494
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003495void dispc_enable_sidle(void)
3496{
3497 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3498}
3499
3500void dispc_disable_sidle(void)
3501{
3502 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3503}
3504
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003505static u32 dispc_mgr_gamma_size(enum omap_channel channel)
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003506{
3507 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3508
3509 if (!dispc.feat->has_gamma_table)
3510 return 0;
3511
3512 return gdesc->len;
3513}
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003514
3515static void dispc_mgr_write_gamma_table(enum omap_channel channel)
3516{
3517 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3518 u32 *table = dispc.gamma_table[channel];
3519 unsigned int i;
3520
3521 DSSDBG("%s: channel %d\n", __func__, channel);
3522
3523 for (i = 0; i < gdesc->len; ++i) {
3524 u32 v = table[i];
3525
3526 if (gdesc->has_index)
3527 v |= i << 24;
3528 else if (i == 0)
3529 v |= 1 << 31;
3530
3531 dispc_write_reg(gdesc->reg, v);
3532 }
3533}
3534
3535static void dispc_restore_gamma_tables(void)
3536{
3537 DSSDBG("%s()\n", __func__);
3538
3539 if (!dispc.feat->has_gamma_table)
3540 return;
3541
3542 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD);
3543
3544 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT);
3545
3546 if (dss_has_feature(FEAT_MGR_LCD2))
3547 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2);
3548
3549 if (dss_has_feature(FEAT_MGR_LCD3))
3550 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3);
3551}
3552
3553static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
3554 { .red = 0, .green = 0, .blue = 0, },
3555 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
3556};
3557
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003558static void dispc_mgr_set_gamma(enum omap_channel channel,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003559 const struct drm_color_lut *lut,
3560 unsigned int length)
3561{
3562 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3563 u32 *table = dispc.gamma_table[channel];
3564 uint i;
3565
3566 DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__,
3567 channel, length, gdesc->len);
3568
3569 if (!dispc.feat->has_gamma_table)
3570 return;
3571
3572 if (lut == NULL || length < 2) {
3573 lut = dispc_mgr_gamma_default_lut;
3574 length = ARRAY_SIZE(dispc_mgr_gamma_default_lut);
3575 }
3576
3577 for (i = 0; i < length - 1; ++i) {
3578 uint first = i * (gdesc->len - 1) / (length - 1);
3579 uint last = (i + 1) * (gdesc->len - 1) / (length - 1);
3580 uint w = last - first;
3581 u16 r, g, b;
3582 uint j;
3583
3584 if (w == 0)
3585 continue;
3586
3587 for (j = 0; j <= w; j++) {
3588 r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
3589 g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
3590 b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
3591
3592 r >>= 16 - gdesc->bits;
3593 g >>= 16 - gdesc->bits;
3594 b >>= 16 - gdesc->bits;
3595
3596 table[first + j] = (r << (gdesc->bits * 2)) |
3597 (g << gdesc->bits) | b;
3598 }
3599 }
3600
3601 if (dispc.is_enabled)
3602 dispc_mgr_write_gamma_table(channel);
3603}
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003604
3605static int dispc_init_gamma_tables(void)
3606{
3607 int channel;
3608
3609 if (!dispc.feat->has_gamma_table)
3610 return 0;
3611
3612 for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) {
3613 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3614 u32 *gt;
3615
3616 if (channel == OMAP_DSS_CHANNEL_LCD2 &&
3617 !dss_has_feature(FEAT_MGR_LCD2))
3618 continue;
3619
3620 if (channel == OMAP_DSS_CHANNEL_LCD3 &&
3621 !dss_has_feature(FEAT_MGR_LCD3))
3622 continue;
3623
3624 gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len,
3625 sizeof(u32), GFP_KERNEL);
3626 if (!gt)
3627 return -ENOMEM;
3628
3629 dispc.gamma_table[channel] = gt;
3630
3631 dispc_mgr_set_gamma(channel, NULL, 0);
3632 }
3633 return 0;
3634}
3635
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003636static void _omap_dispc_initial_config(void)
3637{
3638 u32 l;
3639
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003640 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
3641 if (dss_has_feature(FEAT_CORE_CLK_DIV)) {
3642 l = dispc_read_reg(DISPC_DIVISOR);
3643 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3644 l = FLD_MOD(l, 1, 0, 0);
3645 l = FLD_MOD(l, 1, 23, 16);
3646 dispc_write_reg(DISPC_DIVISOR, l);
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003647
3648 dispc.core_clk_rate = dispc_fclk_rate();
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003649 }
3650
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003651 /* Use gamma table mode, instead of palette mode */
3652 if (dispc.feat->has_gamma_table)
3653 REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3);
3654
3655 /* For older DSS versions (FEAT_FUNCGATED) this enables
3656 * func-clock auto-gating. For newer versions
3657 * (dispc.feat->has_gamma_table) this enables tv-out gamma tables.
3658 */
3659 if (dss_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table)
Archit Taneja6ced40b2010-12-02 11:27:13 +00003660 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003661
Archit Taneja6e5264b2012-09-11 12:04:47 +05303662 dispc_setup_color_conv_coef();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003663
3664 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3665
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003666 dispc_init_fifos();
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03003667
3668 dispc_configure_burst_sizes();
Archit Taneja54128702011-09-08 11:29:17 +05303669
3670 dispc_ovl_enable_zorder_planes();
Archit Tanejad0df9a22013-03-26 19:15:25 +05303671
3672 if (dispc.feat->mstandby_workaround)
3673 REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00003674
3675 if (dss_has_feature(FEAT_MFLAG))
3676 dispc_init_mflag();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003677}
3678
Tomi Valkeinenede92692015-06-04 14:12:16 +03003679static const struct dispc_features omap24xx_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303680 .sw_start = 5,
3681 .fp_start = 15,
3682 .bp_start = 27,
3683 .sw_max = 64,
3684 .vp_max = 255,
3685 .hp_max = 256,
Archit Taneja33b89922012-11-14 13:50:15 +05303686 .mgr_width_start = 10,
3687 .mgr_height_start = 26,
3688 .mgr_width_max = 2048,
3689 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303690 .max_lcd_pclk = 66500000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303691 .calc_scaling = dispc_ovl_calc_scaling_24xx,
3692 .calc_core_clk = calc_core_clk_24xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003693 .num_fifos = 3,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02003694 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303695 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03003696 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303697};
3698
Tomi Valkeinenede92692015-06-04 14:12:16 +03003699static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303700 .sw_start = 5,
3701 .fp_start = 15,
3702 .bp_start = 27,
3703 .sw_max = 64,
3704 .vp_max = 255,
3705 .hp_max = 256,
Archit Taneja33b89922012-11-14 13:50:15 +05303706 .mgr_width_start = 10,
3707 .mgr_height_start = 26,
3708 .mgr_width_max = 2048,
3709 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303710 .max_lcd_pclk = 173000000,
3711 .max_tv_pclk = 59000000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303712 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3713 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003714 .num_fifos = 3,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02003715 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303716 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03003717 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303718};
3719
Tomi Valkeinenede92692015-06-04 14:12:16 +03003720static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303721 .sw_start = 7,
3722 .fp_start = 19,
3723 .bp_start = 31,
3724 .sw_max = 256,
3725 .vp_max = 4095,
3726 .hp_max = 4096,
Archit Taneja33b89922012-11-14 13:50:15 +05303727 .mgr_width_start = 10,
3728 .mgr_height_start = 26,
3729 .mgr_width_max = 2048,
3730 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303731 .max_lcd_pclk = 173000000,
3732 .max_tv_pclk = 59000000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303733 .calc_scaling = dispc_ovl_calc_scaling_34xx,
3734 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003735 .num_fifos = 3,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02003736 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303737 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03003738 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303739};
3740
Tomi Valkeinenede92692015-06-04 14:12:16 +03003741static const struct dispc_features omap44xx_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303742 .sw_start = 7,
3743 .fp_start = 19,
3744 .bp_start = 31,
3745 .sw_max = 256,
3746 .vp_max = 4095,
3747 .hp_max = 4096,
Archit Taneja33b89922012-11-14 13:50:15 +05303748 .mgr_width_start = 10,
3749 .mgr_height_start = 26,
3750 .mgr_width_max = 2048,
3751 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303752 .max_lcd_pclk = 170000000,
3753 .max_tv_pclk = 185625000,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303754 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3755 .calc_core_clk = calc_core_clk_44xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003756 .num_fifos = 5,
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +03003757 .gfx_fifo_workaround = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303758 .set_max_preload = true,
Tomi Valkeinene5f80912015-10-21 13:08:59 +03003759 .supports_sync_align = true,
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02003760 .has_writeback = true,
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02003761 .supports_double_pixel = true,
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02003762 .reverse_ilace_field_order = true,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003763 .has_gamma_table = true,
Jyri Sarhafbff0102016-06-07 15:09:16 +03003764 .has_gamma_i734_bug = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303765};
3766
Tomi Valkeinenede92692015-06-04 14:12:16 +03003767static const struct dispc_features omap54xx_dispc_feats = {
Archit Taneja264236f2012-11-14 13:50:16 +05303768 .sw_start = 7,
3769 .fp_start = 19,
3770 .bp_start = 31,
3771 .sw_max = 256,
3772 .vp_max = 4095,
3773 .hp_max = 4096,
3774 .mgr_width_start = 11,
3775 .mgr_height_start = 27,
3776 .mgr_width_max = 4096,
3777 .mgr_height_max = 4096,
Archit Tanejaca5ca692013-03-26 19:15:22 +05303778 .max_lcd_pclk = 170000000,
3779 .max_tv_pclk = 186000000,
Archit Taneja264236f2012-11-14 13:50:16 +05303780 .calc_scaling = dispc_ovl_calc_scaling_44xx,
3781 .calc_core_clk = calc_core_clk_44xx,
3782 .num_fifos = 5,
3783 .gfx_fifo_workaround = true,
Archit Tanejad0df9a22013-03-26 19:15:25 +05303784 .mstandby_workaround = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05303785 .set_max_preload = true,
Tomi Valkeinene5f80912015-10-21 13:08:59 +03003786 .supports_sync_align = true,
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02003787 .has_writeback = true,
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02003788 .supports_double_pixel = true,
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02003789 .reverse_ilace_field_order = true,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003790 .has_gamma_table = true,
Jyri Sarhafbff0102016-06-07 15:09:16 +03003791 .has_gamma_i734_bug = true,
Archit Taneja264236f2012-11-14 13:50:16 +05303792};
3793
Tomi Valkeinenede92692015-06-04 14:12:16 +03003794static int dispc_init_features(struct platform_device *pdev)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303795{
3796 const struct dispc_features *src;
3797 struct dispc_features *dst;
3798
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003799 dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303800 if (!dst) {
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003801 dev_err(&pdev->dev, "Failed to allocate DISPC Features\n");
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303802 return -ENOMEM;
3803 }
3804
Tomi Valkeinenb2c7d542012-10-18 13:46:29 +03003805 switch (omapdss_get_version()) {
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003806 case OMAPDSS_VER_OMAP24xx:
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303807 src = &omap24xx_dispc_feats;
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003808 break;
3809
3810 case OMAPDSS_VER_OMAP34xx_ES1:
3811 src = &omap34xx_rev1_0_dispc_feats;
3812 break;
3813
3814 case OMAPDSS_VER_OMAP34xx_ES3:
3815 case OMAPDSS_VER_OMAP3630:
3816 case OMAPDSS_VER_AM35xx:
Sathya Prakash M Rd6279d42014-03-24 16:31:51 +05303817 case OMAPDSS_VER_AM43xx:
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003818 src = &omap34xx_rev3_0_dispc_feats;
3819 break;
3820
3821 case OMAPDSS_VER_OMAP4430_ES1:
3822 case OMAPDSS_VER_OMAP4430_ES2:
3823 case OMAPDSS_VER_OMAP4:
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303824 src = &omap44xx_dispc_feats;
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003825 break;
3826
3827 case OMAPDSS_VER_OMAP5:
Tomi Valkeinen93550922014-12-31 11:25:48 +02003828 case OMAPDSS_VER_DRA7xx:
Archit Taneja264236f2012-11-14 13:50:16 +05303829 src = &omap54xx_dispc_feats;
Tomi Valkeinen84b476232012-09-28 12:54:03 +03003830 break;
3831
3832 default:
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05303833 return -ENODEV;
3834 }
3835
3836 memcpy(dst, src, sizeof(*dst));
3837 dispc.feat = dst;
3838
3839 return 0;
3840}
3841
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03003842static irqreturn_t dispc_irq_handler(int irq, void *arg)
3843{
3844 if (!dispc.is_enabled)
3845 return IRQ_NONE;
3846
3847 return dispc.user_handler(irq, dispc.user_data);
3848}
3849
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003850static int dispc_request_irq(irq_handler_t handler, void *dev_id)
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03003851{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03003852 int r;
3853
3854 if (dispc.user_handler != NULL)
3855 return -EBUSY;
3856
3857 dispc.user_handler = handler;
3858 dispc.user_data = dev_id;
3859
3860 /* ensure the dispc_irq_handler sees the values above */
3861 smp_wmb();
3862
3863 r = devm_request_irq(&dispc.pdev->dev, dispc.irq, dispc_irq_handler,
3864 IRQF_SHARED, "OMAP DISPC", &dispc);
3865 if (r) {
3866 dispc.user_handler = NULL;
3867 dispc.user_data = NULL;
3868 }
3869
3870 return r;
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03003871}
3872
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +02003873static void dispc_free_irq(void *dev_id)
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03003874{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03003875 devm_free_irq(&dispc.pdev->dev, dispc.irq, &dispc);
3876
3877 dispc.user_handler = NULL;
3878 dispc.user_data = NULL;
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03003879}
3880
Jyri Sarhafbff0102016-06-07 15:09:16 +03003881/*
3882 * Workaround for errata i734 in DSS dispc
3883 * - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
3884 *
3885 * For gamma tables to work on LCD1 the GFX plane has to be used at
3886 * least once after DSS HW has come out of reset. The workaround
3887 * sets up a minimal LCD setup with GFX plane and waits for one
3888 * vertical sync irq before disabling the setup and continuing with
3889 * the context restore. The physical outputs are gated during the
3890 * operation. This workaround requires that gamma table's LOADMODE
3891 * is set to 0x2 in DISPC_CONTROL1 register.
3892 *
3893 * For details see:
3894 * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata
3895 * Literature Number: SWPZ037E
3896 * Or some other relevant errata document for the DSS IP version.
3897 */
3898
3899static const struct dispc_errata_i734_data {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003900 struct videomode vm;
Jyri Sarhafbff0102016-06-07 15:09:16 +03003901 struct omap_overlay_info ovli;
3902 struct omap_overlay_manager_info mgri;
3903 struct dss_lcd_mgr_config lcd_conf;
3904} i734 = {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003905 .vm = {
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003906 .hactive = 8, .vactive = 1,
Jyri Sarhafbff0102016-06-07 15:09:16 +03003907 .pixelclock = 16000000,
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03003908 .hsync_len = 8, .hfront_porch = 4, .hback_porch = 4,
Peter Ujfalusi458540c2016-09-22 14:06:53 +03003909 .vsync_len = 1, .vfront_porch = 1, .vback_porch = 1,
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03003910
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +03003911 .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
Peter Ujfalusid34afb72016-09-22 14:07:01 +03003912 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
3913 DISPLAY_FLAGS_PIXDATA_POSEDGE,
Jyri Sarhafbff0102016-06-07 15:09:16 +03003914 },
3915 .ovli = {
3916 .screen_width = 1,
3917 .width = 1, .height = 1,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03003918 .fourcc = DRM_FORMAT_XRGB8888,
Jyri Sarhafbff0102016-06-07 15:09:16 +03003919 .rotation = OMAP_DSS_ROT_0,
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03003920 .rotation_type = OMAP_DSS_ROT_NONE,
Jyri Sarhafbff0102016-06-07 15:09:16 +03003921 .mirror = 0,
3922 .pos_x = 0, .pos_y = 0,
3923 .out_width = 0, .out_height = 0,
3924 .global_alpha = 0xff,
3925 .pre_mult_alpha = 0,
3926 .zorder = 0,
3927 },
3928 .mgri = {
3929 .default_color = 0,
3930 .trans_enabled = false,
3931 .partial_alpha_enabled = false,
3932 .cpr_enable = false,
3933 },
3934 .lcd_conf = {
3935 .io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
3936 .stallmode = false,
3937 .fifohandcheck = false,
3938 .clock_info = {
3939 .lck_div = 1,
3940 .pck_div = 2,
3941 },
3942 .video_port_width = 24,
3943 .lcden_sig_polarity = 0,
3944 },
3945};
3946
3947static struct i734_buf {
3948 size_t size;
3949 dma_addr_t paddr;
3950 void *vaddr;
3951} i734_buf;
3952
3953static int dispc_errata_i734_wa_init(void)
3954{
3955 if (!dispc.feat->has_gamma_i734_bug)
3956 return 0;
3957
3958 i734_buf.size = i734.ovli.width * i734.ovli.height *
Tomi Valkeinen41aff422017-05-04 11:31:56 +03003959 color_mode_to_bpp(i734.ovli.fourcc) / 8;
Jyri Sarhafbff0102016-06-07 15:09:16 +03003960
3961 i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size,
3962 &i734_buf.paddr, GFP_KERNEL);
3963 if (!i734_buf.vaddr) {
3964 dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed",
3965 __func__);
3966 return -ENOMEM;
3967 }
3968
3969 return 0;
3970}
3971
3972static void dispc_errata_i734_wa_fini(void)
3973{
3974 if (!dispc.feat->has_gamma_i734_bug)
3975 return;
3976
3977 dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr,
3978 i734_buf.paddr);
3979}
3980
3981static void dispc_errata_i734_wa(void)
3982{
3983 u32 framedone_irq = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_LCD);
3984 struct omap_overlay_info ovli;
3985 struct dss_lcd_mgr_config lcd_conf;
3986 u32 gatestate;
3987 unsigned int count;
3988
3989 if (!dispc.feat->has_gamma_i734_bug)
3990 return;
3991
3992 gatestate = REG_GET(DISPC_CONFIG, 8, 4);
3993
3994 ovli = i734.ovli;
3995 ovli.paddr = i734_buf.paddr;
3996 lcd_conf = i734.lcd_conf;
3997
3998 /* Gate all LCD1 outputs */
3999 REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4);
4000
4001 /* Setup and enable GFX plane */
Tomi Valkeinen49a30572017-02-17 12:30:07 +02004002 dispc_ovl_setup(OMAP_DSS_GFX, &ovli, &i734.vm, false,
4003 OMAP_DSS_CHANNEL_LCD);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004004 dispc_ovl_enable(OMAP_DSS_GFX, true);
4005
4006 /* Set up and enable display manager for LCD1 */
4007 dispc_mgr_setup(OMAP_DSS_CHANNEL_LCD, &i734.mgri);
4008 dispc_calc_clock_rates(dss_get_dispc_clk_rate(),
4009 &lcd_conf.clock_info);
4010 dispc_mgr_set_lcd_config(OMAP_DSS_CHANNEL_LCD, &lcd_conf);
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004011 dispc_mgr_set_timings(OMAP_DSS_CHANNEL_LCD, &i734.vm);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004012
4013 dispc_clear_irqstatus(framedone_irq);
4014
4015 /* Enable and shut the channel to produce just one frame */
4016 dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, true);
4017 dispc_mgr_enable(OMAP_DSS_CHANNEL_LCD, false);
4018
4019 /* Busy wait for framedone. We can't fiddle with irq handlers
4020 * in PM resume. Typically the loop runs less than 5 times and
4021 * waits less than a micro second.
4022 */
4023 count = 0;
4024 while (!(dispc_read_irqstatus() & framedone_irq)) {
4025 if (count++ > 10000) {
4026 dev_err(&dispc.pdev->dev, "%s: framedone timeout\n",
4027 __func__);
4028 break;
4029 }
4030 }
4031 dispc_ovl_enable(OMAP_DSS_GFX, false);
4032
4033 /* Clear all irq bits before continuing */
4034 dispc_clear_irqstatus(0xffffffff);
4035
4036 /* Restore the original state to LCD1 output gates */
4037 REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4);
4038}
4039
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004040static const struct dispc_ops dispc_ops = {
4041 .read_irqstatus = dispc_read_irqstatus,
4042 .clear_irqstatus = dispc_clear_irqstatus,
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004043 .write_irqenable = dispc_write_irqenable,
4044
4045 .request_irq = dispc_request_irq,
4046 .free_irq = dispc_free_irq,
4047
4048 .runtime_get = dispc_runtime_get,
4049 .runtime_put = dispc_runtime_put,
4050
4051 .get_num_ovls = dispc_get_num_ovls,
4052 .get_num_mgrs = dispc_get_num_mgrs,
4053
4054 .mgr_enable = dispc_mgr_enable,
4055 .mgr_is_enabled = dispc_mgr_is_enabled,
4056 .mgr_get_vsync_irq = dispc_mgr_get_vsync_irq,
4057 .mgr_get_framedone_irq = dispc_mgr_get_framedone_irq,
4058 .mgr_get_sync_lost_irq = dispc_mgr_get_sync_lost_irq,
4059 .mgr_go_busy = dispc_mgr_go_busy,
4060 .mgr_go = dispc_mgr_go,
4061 .mgr_set_lcd_config = dispc_mgr_set_lcd_config,
4062 .mgr_set_timings = dispc_mgr_set_timings,
4063 .mgr_setup = dispc_mgr_setup,
4064 .mgr_get_supported_outputs = dispc_mgr_get_supported_outputs,
4065 .mgr_gamma_size = dispc_mgr_gamma_size,
4066 .mgr_set_gamma = dispc_mgr_set_gamma,
4067
4068 .ovl_enable = dispc_ovl_enable,
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004069 .ovl_setup = dispc_ovl_setup,
4070 .ovl_get_color_modes = dispc_ovl_get_color_modes,
4071};
4072
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004073/* DISPC HW IP initialisation */
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004074static int dispc_bind(struct device *dev, struct device *master, void *data)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004075{
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004076 struct platform_device *pdev = to_platform_device(dev);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004077 u32 rev;
archit tanejaaffe3602011-02-23 08:41:03 +00004078 int r = 0;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004079 struct resource *dispc_mem;
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00004080 struct device_node *np = pdev->dev.of_node;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004081
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004082 dispc.pdev = pdev;
4083
Tomi Valkeinend49cd152014-11-10 12:23:00 +02004084 spin_lock_init(&dispc.control_lock);
4085
Tomi Valkeinen84b476232012-09-28 12:54:03 +03004086 r = dispc_init_features(dispc.pdev);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304087 if (r)
4088 return r;
4089
Jyri Sarhafbff0102016-06-07 15:09:16 +03004090 r = dispc_errata_i734_wa_init();
4091 if (r)
4092 return r;
4093
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004094 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
Laurent Pinchartb22622f2017-05-07 00:29:09 +03004095 dispc.base = devm_ioremap_resource(&pdev->dev, dispc_mem);
4096 if (IS_ERR(dispc.base))
4097 return PTR_ERR(dispc.base);
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004098
archit tanejaaffe3602011-02-23 08:41:03 +00004099 dispc.irq = platform_get_irq(dispc.pdev, 0);
4100 if (dispc.irq < 0) {
4101 DSSERR("platform_get_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004102 return -ENODEV;
archit tanejaaffe3602011-02-23 08:41:03 +00004103 }
4104
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00004105 if (np && of_property_read_bool(np, "syscon-pol")) {
4106 dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
4107 if (IS_ERR(dispc.syscon_pol)) {
4108 dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
4109 return PTR_ERR(dispc.syscon_pol);
4110 }
4111
4112 if (of_property_read_u32_index(np, "syscon-pol", 1,
4113 &dispc.syscon_pol_offset)) {
4114 dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
4115 return -EINVAL;
4116 }
4117 }
4118
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004119 r = dispc_init_gamma_tables();
4120 if (r)
4121 return r;
4122
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004123 pm_runtime_enable(&pdev->dev);
4124
4125 r = dispc_runtime_get();
4126 if (r)
4127 goto err_runtime_get;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004128
4129 _omap_dispc_initial_config();
4130
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004131 rev = dispc_read_reg(DISPC_REVISION);
Sumit Semwala06b62f2011-01-24 06:22:03 +00004132 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004133 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4134
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004135 dispc_runtime_put();
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004136
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004137 dispc_set_ops(&dispc_ops);
4138
Tomi Valkeinene40402c2012-03-02 18:01:07 +02004139 dss_debugfs_create_file("dispc", dispc_dump_regs);
4140
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004141 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004142
4143err_runtime_get:
4144 pm_runtime_disable(&pdev->dev);
archit tanejaaffe3602011-02-23 08:41:03 +00004145 return r;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004146}
4147
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004148static void dispc_unbind(struct device *dev, struct device *master,
4149 void *data)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004150{
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004151 dispc_set_ops(NULL);
4152
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004153 pm_runtime_disable(dev);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004154
4155 dispc_errata_i734_wa_fini();
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004156}
Tomi Valkeinen04b1fc02013-05-14 10:55:19 +03004157
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004158static const struct component_ops dispc_component_ops = {
4159 .bind = dispc_bind,
4160 .unbind = dispc_unbind,
4161};
4162
4163static int dispc_probe(struct platform_device *pdev)
4164{
4165 return component_add(&pdev->dev, &dispc_component_ops);
4166}
4167
4168static int dispc_remove(struct platform_device *pdev)
4169{
4170 component_del(&pdev->dev, &dispc_component_ops);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004171 return 0;
4172}
4173
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004174static int dispc_runtime_suspend(struct device *dev)
4175{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004176 dispc.is_enabled = false;
4177 /* ensure the dispc_irq_handler sees the is_enabled value */
4178 smp_wmb();
4179 /* wait for current handler to finish before turning the DISPC off */
4180 synchronize_irq(dispc.irq);
4181
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004182 dispc_save_context();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004183
4184 return 0;
4185}
4186
4187static int dispc_runtime_resume(struct device *dev)
4188{
Tomi Valkeinen9229b512014-02-14 09:37:09 +02004189 /*
4190 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
4191 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
4192 * _omap_dispc_initial_config(). We can thus use it to detect if
4193 * we have lost register context.
4194 */
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004195 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
4196 _omap_dispc_initial_config();
Tomi Valkeinen9229b512014-02-14 09:37:09 +02004197
Jyri Sarhafbff0102016-06-07 15:09:16 +03004198 dispc_errata_i734_wa();
4199
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004200 dispc_restore_context();
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004201
4202 dispc_restore_gamma_tables();
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004203 }
Tomi Valkeinenbe07dcd72013-11-21 16:01:40 +02004204
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004205 dispc.is_enabled = true;
4206 /* ensure the dispc_irq_handler sees the is_enabled value */
4207 smp_wmb();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004208
4209 return 0;
4210}
4211
4212static const struct dev_pm_ops dispc_pm_ops = {
4213 .runtime_suspend = dispc_runtime_suspend,
4214 .runtime_resume = dispc_runtime_resume,
4215};
4216
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004217static const struct of_device_id dispc_of_match[] = {
4218 { .compatible = "ti,omap2-dispc", },
4219 { .compatible = "ti,omap3-dispc", },
4220 { .compatible = "ti,omap4-dispc", },
Tomi Valkeinen2e7e6b62014-04-16 13:16:43 +03004221 { .compatible = "ti,omap5-dispc", },
Tomi Valkeinen93550922014-12-31 11:25:48 +02004222 { .compatible = "ti,dra7-dispc", },
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004223 {},
4224};
4225
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004226static struct platform_driver omap_dispchw_driver = {
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004227 .probe = dispc_probe,
4228 .remove = dispc_remove,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004229 .driver = {
4230 .name = "omapdss_dispc",
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004231 .pm = &dispc_pm_ops,
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004232 .of_match_table = dispc_of_match,
Tomi Valkeinen422ccbd2014-10-16 09:54:25 +03004233 .suppress_bind_attrs = true,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004234 },
4235};
4236
Tomi Valkeinen6e7e8f02012-02-17 17:41:13 +02004237int __init dispc_init_platform_driver(void)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004238{
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004239 return platform_driver_register(&omap_dispchw_driver);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004240}
4241
Tomi Valkeinenede92692015-06-04 14:12:16 +03004242void dispc_uninit_platform_driver(void)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004243{
Tomi Valkeinen04c742c2012-02-23 15:32:37 +02004244 platform_driver_unregister(&omap_dispchw_driver);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004245}