blob: bd014bfc1cb60ade9b8b7b20562754831d58eff0 [file] [log] [blame]
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001/*
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002 * Copyright (C) 2009 Nokia Corporation
3 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4 *
5 * Some code and ideas taken from drivers/video/omap/ driver
6 * by Imre Deak.
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License version 2 as published by
10 * the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#define DSS_SUBSYS_NAME "DISPC"
22
23#include <linux/kernel.h>
24#include <linux/dma-mapping.h>
25#include <linux/vmalloc.h>
Paul Gortmakera8a35932011-07-10 13:20:26 -040026#include <linux/export.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020027#include <linux/clk.h>
28#include <linux/io.h>
29#include <linux/jiffies.h>
30#include <linux/seq_file.h>
31#include <linux/delay.h>
32#include <linux/workqueue.h>
Tomi Valkeinenab83b142010-06-09 15:31:01 +030033#include <linux/hardirq.h>
Tomi Valkeinen24e62892011-05-23 11:51:18 +030034#include <linux/platform_device.h>
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +030035#include <linux/pm_runtime.h>
Tomi Valkeinen33366d02012-09-28 13:54:35 +030036#include <linux/sizes.h>
Tomi Valkeinen0006fd62014-09-05 19:15:03 +000037#include <linux/mfd/syscon.h>
38#include <linux/regmap.h>
39#include <linux/of.h>
Laurent Pinchart7a143a42017-08-05 01:43:55 +030040#include <linux/of_device.h>
Tomi Valkeinen736e60d2015-06-04 15:22:23 +030041#include <linux/component.h>
Laurent Pinchart7a143a42017-08-05 01:43:55 +030042#include <linux/sys_soc.h>
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +030043#include <drm/drm_fourcc.h>
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +030044#include <drm/drm_blend.h>
Tomi Valkeinen80c39712009-11-12 11:41:42 +020045
Peter Ujfalusi32043da2016-05-27 14:40:49 +030046#include "omapdss.h"
Tomi Valkeinen80c39712009-11-12 11:41:42 +020047#include "dss.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
Laurent Pinchart1ac0c892017-08-05 01:44:14 +030065/* DISPC has feature id */
66enum dispc_feature_id {
67 FEAT_LCDENABLEPOL,
68 FEAT_LCDENABLESIGNAL,
69 FEAT_PCKFREEENABLE,
70 FEAT_FUNCGATED,
71 FEAT_MGR_LCD2,
72 FEAT_MGR_LCD3,
73 FEAT_LINEBUFFERSPLIT,
74 FEAT_ROWREPEATENABLE,
75 FEAT_RESIZECONF,
76 /* Independent core clk divider */
77 FEAT_CORE_CLK_DIV,
78 FEAT_HANDLE_UV_SEPARATE,
79 FEAT_ATTR2,
80 FEAT_CPR,
81 FEAT_PRELOAD,
82 FEAT_FIR_COEF_V,
83 FEAT_ALPHA_FIXED_ZORDER,
84 FEAT_ALPHA_FREE_ZORDER,
85 FEAT_FIFO_MERGE,
86 /* An unknown HW bug causing the normal FIFO thresholds not to work */
87 FEAT_OMAP3_DSI_FIFO_BUG,
88 FEAT_BURST_2D,
89 FEAT_MFLAG,
90};
91
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +053092struct dispc_features {
93 u8 sw_start;
94 u8 fp_start;
95 u8 bp_start;
96 u16 sw_max;
97 u16 vp_max;
98 u16 hp_max;
Archit Taneja33b89922012-11-14 13:50:15 +053099 u8 mgr_width_start;
100 u8 mgr_height_start;
101 u16 mgr_width_max;
102 u16 mgr_height_max;
Archit Tanejaca5ca692013-03-26 19:15:22 +0530103 unsigned long max_lcd_pclk;
104 unsigned long max_tv_pclk;
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +0300105 unsigned int max_downscale;
106 unsigned int max_line_width;
107 unsigned int min_pcd;
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +0300108 int (*calc_scaling) (unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +0300109 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530110 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +0300111 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530112 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +0530113 u16 pos_x, unsigned long *core_clk, bool mem_to_mem);
Tomi Valkeinen8702ee52012-10-19 15:36:11 +0300114 unsigned long (*calc_core_clk) (unsigned long pclk,
Archit Taneja8ba85302012-09-26 17:00:37 +0530115 u16 width, u16 height, u16 out_width, u16 out_height,
116 bool mem_to_mem);
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300117 u8 num_fifos;
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300118 const enum dispc_feature_id *features;
119 unsigned int num_features;
Laurent Pinchart38dc0702017-08-05 01:44:08 +0300120 const struct dss_reg_field *reg_fields;
121 const unsigned int num_reg_fields;
Laurent Pinchartfcd41882017-08-05 01:44:05 +0300122 const enum omap_overlay_caps *overlay_caps;
Laurent Pinchart94f96ad2017-08-05 01:44:04 +0300123 const u32 **supported_color_modes;
Laurent Pinchartacf591c2017-08-05 01:44:06 +0300124 unsigned int num_mgrs;
125 unsigned int num_ovls;
Laurent Pinchart28550472017-08-05 01:44:03 +0300126 unsigned int buffer_size_unit;
127 unsigned int burst_size_unit;
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +0300128
129 /* swap GFX & WB fifos */
130 bool gfx_fifo_workaround:1;
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200131
132 /* no DISPC_IRQ_FRAMEDONETV on this SoC */
133 bool no_framedone_tv:1;
Archit Tanejad0df9a22013-03-26 19:15:25 +0530134
135 /* revert to the OMAP4 mechanism of DISPC Smart Standby operation */
136 bool mstandby_workaround:1;
Archit Taneja8bc65552013-12-17 16:40:21 +0530137
138 bool set_max_preload:1;
Tomi Valkeinenf2aee312015-04-10 12:48:34 +0300139
140 /* PIXEL_INC is not added to the last pixel of a line */
141 bool last_pixel_inc_missing:1;
Tomi Valkeinene5f80912015-10-21 13:08:59 +0300142
143 /* POL_FREQ has ALIGN bit */
144 bool supports_sync_align:1;
Tomi Valkeinen20efbc32015-11-04 17:10:44 +0200145
146 bool has_writeback:1;
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +0200147
148 bool supports_double_pixel:1;
Tomi Valkeinenb7536d62016-01-13 18:41:36 +0200149
150 /*
151 * Field order for VENC is different than HDMI. We should handle this in
152 * some intelligent manner, but as the SoCs have either HDMI or VENC,
153 * never both, we can just use this flag for now.
154 */
155 bool reverse_ilace_field_order:1;
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300156
157 bool has_gamma_table:1;
Jyri Sarhafbff0102016-06-07 15:09:16 +0300158
159 bool has_gamma_i734_bug:1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530160};
161
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300162#define DISPC_MAX_NR_FIFOS 5
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300163#define DISPC_MAX_CHANNEL_GAMMA 4
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300164
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200165struct dispc_device {
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +0000166 struct platform_device *pdev;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200167 void __iomem *base;
Laurent Pinchart3cc62aa2018-02-13 14:00:25 +0200168 struct dss_device *dss;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300169
Laurent Pinchartf33656e2018-02-13 14:00:29 +0200170 struct dss_debugfs_entry *debugfs;
171
archit tanejaaffe3602011-02-23 08:41:03 +0000172 int irq;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +0300173 irq_handler_t user_handler;
174 void *user_data;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200175
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +0200176 unsigned long core_clk_rate;
Tomi Valkeinen5391e872013-05-16 10:44:13 +0300177 unsigned long tv_pclk_rate;
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +0200178
Tomi Valkeinen42a69612012-08-22 16:56:57 +0300179 u32 fifo_size[DISPC_MAX_NR_FIFOS];
180 /* maps which plane is using a fifo. fifo-id -> plane-id */
181 int fifo_assignment[DISPC_MAX_NR_FIFOS];
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200182
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300183 bool ctx_valid;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200184 u32 ctx[DISPC_SZ_REGS / sizeof(u32)];
Tomi Valkeinendfc0fd82009-12-17 14:35:21 +0200185
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300186 u32 *gamma_table[DISPC_MAX_CHANNEL_GAMMA];
187
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +0530188 const struct dispc_features *feat;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +0300189
190 bool is_enabled;
Tomi Valkeinen0006fd62014-09-05 19:15:03 +0000191
192 struct regmap *syscon_pol;
193 u32 syscon_pol_offset;
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200194
195 /* DISPC_CONTROL & DISPC_CONFIG lock*/
196 spinlock_t control_lock;
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200197};
198
199static struct dispc_device dispc;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200200
Amber Jain0d66cbb2011-05-19 19:47:54 +0530201enum omap_color_component {
202 /* used for all color formats for OMAP3 and earlier
203 * and for RGB and Y color component on OMAP4
204 */
205 DISPC_COLOR_COMPONENT_RGB_Y = 1 << 0,
206 /* used for UV component for
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +0300207 * DRM_FORMAT_YUYV, DRM_FORMAT_UYVY, DRM_FORMAT_NV12
Amber Jain0d66cbb2011-05-19 19:47:54 +0530208 * color formats on OMAP4
209 */
210 DISPC_COLOR_COMPONENT_UV = 1 << 1,
211};
212
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530213enum mgr_reg_fields {
214 DISPC_MGR_FLD_ENABLE,
215 DISPC_MGR_FLD_STNTFT,
216 DISPC_MGR_FLD_GO,
217 DISPC_MGR_FLD_TFTDATALINES,
218 DISPC_MGR_FLD_STALLMODE,
219 DISPC_MGR_FLD_TCKENABLE,
220 DISPC_MGR_FLD_TCKSELECTION,
221 DISPC_MGR_FLD_CPR,
222 DISPC_MGR_FLD_FIFOHANDCHECK,
223 /* used to maintain a count of the above fields */
224 DISPC_MGR_FLD_NUM,
225};
226
Laurent Pinchart38dc0702017-08-05 01:44:08 +0300227/* DISPC register field id */
228enum dispc_feat_reg_field {
229 FEAT_REG_FIRHINC,
230 FEAT_REG_FIRVINC,
231 FEAT_REG_FIFOHIGHTHRESHOLD,
232 FEAT_REG_FIFOLOWTHRESHOLD,
233 FEAT_REG_FIFOSIZE,
234 FEAT_REG_HORIZONTALACCU,
235 FEAT_REG_VERTICALACCU,
236};
237
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300238struct dispc_reg_field {
239 u16 reg;
240 u8 high;
241 u8 low;
242};
243
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300244struct dispc_gamma_desc {
245 u32 len;
246 u32 bits;
247 u16 reg;
248 bool has_index;
249};
250
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530251static const struct {
252 const char *name;
253 u32 vsync_irq;
254 u32 framedone_irq;
255 u32 sync_lost_irq;
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300256 struct dispc_gamma_desc gamma;
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300257 struct dispc_reg_field reg_desc[DISPC_MGR_FLD_NUM];
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530258} mgr_desc[] = {
259 [OMAP_DSS_CHANNEL_LCD] = {
260 .name = "LCD",
261 .vsync_irq = DISPC_IRQ_VSYNC,
262 .framedone_irq = DISPC_IRQ_FRAMEDONE,
263 .sync_lost_irq = DISPC_IRQ_SYNC_LOST,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300264 .gamma = {
265 .len = 256,
266 .bits = 8,
267 .reg = DISPC_GAMMA_TABLE0,
268 .has_index = true,
269 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530270 .reg_desc = {
271 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 },
272 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 },
273 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 },
274 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 },
275 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 },
276 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 },
277 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 },
278 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 },
279 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
280 },
281 },
282 [OMAP_DSS_CHANNEL_DIGIT] = {
283 .name = "DIGIT",
284 .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN,
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200285 .framedone_irq = DISPC_IRQ_FRAMEDONETV,
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530286 .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300287 .gamma = {
288 .len = 1024,
289 .bits = 10,
290 .reg = DISPC_GAMMA_TABLE2,
291 .has_index = false,
292 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530293 .reg_desc = {
294 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 },
295 [DISPC_MGR_FLD_STNTFT] = { },
296 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 },
297 [DISPC_MGR_FLD_TFTDATALINES] = { },
298 [DISPC_MGR_FLD_STALLMODE] = { },
299 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 },
300 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 },
301 [DISPC_MGR_FLD_CPR] = { },
302 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 },
303 },
304 },
305 [OMAP_DSS_CHANNEL_LCD2] = {
306 .name = "LCD2",
307 .vsync_irq = DISPC_IRQ_VSYNC2,
308 .framedone_irq = DISPC_IRQ_FRAMEDONE2,
309 .sync_lost_irq = DISPC_IRQ_SYNC_LOST2,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300310 .gamma = {
311 .len = 256,
312 .bits = 8,
313 .reg = DISPC_GAMMA_TABLE1,
314 .has_index = true,
315 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530316 .reg_desc = {
317 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 },
318 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 },
319 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 },
320 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 },
321 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 },
322 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 },
323 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 },
324 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 },
325 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 },
326 },
327 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530328 [OMAP_DSS_CHANNEL_LCD3] = {
329 .name = "LCD3",
330 .vsync_irq = DISPC_IRQ_VSYNC3,
331 .framedone_irq = DISPC_IRQ_FRAMEDONE3,
332 .sync_lost_irq = DISPC_IRQ_SYNC_LOST3,
Jyri Sarhaacc3a232016-06-07 15:09:15 +0300333 .gamma = {
334 .len = 256,
335 .bits = 8,
336 .reg = DISPC_GAMMA_TABLE3,
337 .has_index = true,
338 },
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530339 .reg_desc = {
340 [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 },
341 [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 },
342 [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 },
343 [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 },
344 [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 },
345 [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 },
346 [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 },
347 [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 },
348 [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 },
349 },
350 },
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530351};
352
Archit Taneja6e5264b2012-09-11 12:04:47 +0530353struct color_conv_coef {
354 int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb;
355 int full_range;
356};
357
Tomi Valkeinen65904152015-11-04 17:10:57 +0200358static unsigned long dispc_fclk_rate(void);
359static unsigned long dispc_core_clk_rate(void);
360static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel);
361static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel);
362
Jyri Sarha864050c2017-03-24 16:47:52 +0200363static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane);
364static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200365
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200366static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask);
Tomi Valkeinen5034b1f2015-11-05 20:06:06 +0200367
Archit Taneja55978cc2011-05-06 11:45:51 +0530368static inline void dispc_write_reg(const u16 idx, u32 val)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200369{
Archit Taneja55978cc2011-05-06 11:45:51 +0530370 __raw_writel(val, dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200371}
372
Archit Taneja55978cc2011-05-06 11:45:51 +0530373static inline u32 dispc_read_reg(const u16 idx)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200374{
Archit Taneja55978cc2011-05-06 11:45:51 +0530375 return __raw_readl(dispc.base + idx);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200376}
377
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530378static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld)
379{
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300380 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530381 return REG_GET(rfld.reg, rfld.high, rfld.low);
382}
383
384static void mgr_fld_write(enum omap_channel channel,
385 enum mgr_reg_fields regfld, int val) {
Jyri Sarha5c348ba2014-04-11 16:25:06 +0300386 const struct dispc_reg_field rfld = mgr_desc[channel].reg_desc[regfld];
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200387 const bool need_lock = rfld.reg == DISPC_CONTROL || rfld.reg == DISPC_CONFIG;
388 unsigned long flags;
389
390 if (need_lock)
391 spin_lock_irqsave(&dispc.control_lock, flags);
392
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530393 REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low);
Tomi Valkeinend49cd152014-11-10 12:23:00 +0200394
395 if (need_lock)
396 spin_unlock_irqrestore(&dispc.control_lock, flags);
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530397}
398
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200399static int dispc_get_num_ovls(struct dispc_device *dispc)
Laurent Pinchartacf591c2017-08-05 01:44:06 +0300400{
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200401 return dispc->feat->num_ovls;
Laurent Pinchartacf591c2017-08-05 01:44:06 +0300402}
403
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200404static int dispc_get_num_mgrs(struct dispc_device *dispc)
Laurent Pinchartacf591c2017-08-05 01:44:06 +0300405{
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200406 return dispc->feat->num_mgrs;
Laurent Pinchartacf591c2017-08-05 01:44:06 +0300407}
408
Laurent Pinchart38dc0702017-08-05 01:44:08 +0300409static void dispc_get_reg_field(enum dispc_feat_reg_field id,
410 u8 *start, u8 *end)
411{
412 if (id >= dispc.feat->num_reg_fields)
413 BUG();
414
415 *start = dispc.feat->reg_fields[id].start;
416 *end = dispc.feat->reg_fields[id].end;
417}
418
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300419static bool dispc_has_feature(enum dispc_feature_id id)
420{
421 unsigned int i;
422
423 for (i = 0; i < dispc.feat->num_features; i++) {
424 if (dispc.feat->features[i] == id)
425 return true;
426 }
427
428 return false;
429}
430
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200431#define SR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530432 dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200433#define RR(reg) \
Archit Taneja55978cc2011-05-06 11:45:51 +0530434 dispc_write_reg(DISPC_##reg, dispc.ctx[DISPC_##reg / sizeof(u32)])
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200435
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300436static void dispc_save_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200437{
Archit Tanejac6104b82011-08-05 19:06:02 +0530438 int i, j;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200439
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300440 DSSDBG("dispc_save_context\n");
441
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200442 SR(IRQENABLE);
443 SR(CONTROL);
444 SR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200445 SR(LINE_NUMBER);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300446 if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
447 dispc_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300448 SR(GLOBAL_ALPHA);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300449 if (dispc_has_feature(FEAT_MGR_LCD2)) {
Sumit Semwal2a205f32010-12-02 11:27:12 +0000450 SR(CONTROL2);
Sumit Semwal2a205f32010-12-02 11:27:12 +0000451 SR(CONFIG2);
452 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300453 if (dispc_has_feature(FEAT_MGR_LCD3)) {
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530454 SR(CONTROL3);
455 SR(CONFIG3);
456 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200457
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200458 for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530459 SR(DEFAULT_COLOR(i));
460 SR(TRANS_COLOR(i));
461 SR(SIZE_MGR(i));
462 if (i == OMAP_DSS_CHANNEL_DIGIT)
463 continue;
464 SR(TIMING_H(i));
465 SR(TIMING_V(i));
466 SR(POL_FREQ(i));
467 SR(DIVISORo(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200468
Archit Tanejac6104b82011-08-05 19:06:02 +0530469 SR(DATA_CYCLE1(i));
470 SR(DATA_CYCLE2(i));
471 SR(DATA_CYCLE3(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200472
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300473 if (dispc_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530474 SR(CPR_COEF_R(i));
475 SR(CPR_COEF_G(i));
476 SR(CPR_COEF_B(i));
477 }
478 }
479
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200480 for (i = 0; i < dispc_get_num_ovls(&dispc); i++) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530481 SR(OVL_BA0(i));
482 SR(OVL_BA1(i));
483 SR(OVL_POSITION(i));
484 SR(OVL_SIZE(i));
485 SR(OVL_ATTRIBUTES(i));
486 SR(OVL_FIFO_THRESHOLD(i));
487 SR(OVL_ROW_INC(i));
488 SR(OVL_PIXEL_INC(i));
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300489 if (dispc_has_feature(FEAT_PRELOAD))
Archit Tanejac6104b82011-08-05 19:06:02 +0530490 SR(OVL_PRELOAD(i));
491 if (i == OMAP_DSS_GFX) {
492 SR(OVL_WINDOW_SKIP(i));
493 SR(OVL_TABLE_BA(i));
494 continue;
495 }
496 SR(OVL_FIR(i));
497 SR(OVL_PICTURE_SIZE(i));
498 SR(OVL_ACCU0(i));
499 SR(OVL_ACCU1(i));
500
501 for (j = 0; j < 8; j++)
502 SR(OVL_FIR_COEF_H(i, j));
503
504 for (j = 0; j < 8; j++)
505 SR(OVL_FIR_COEF_HV(i, j));
506
507 for (j = 0; j < 5; j++)
508 SR(OVL_CONV_COEF(i, j));
509
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300510 if (dispc_has_feature(FEAT_FIR_COEF_V)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530511 for (j = 0; j < 8; j++)
512 SR(OVL_FIR_COEF_V(i, j));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300513 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000514
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300515 if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530516 SR(OVL_BA0_UV(i));
517 SR(OVL_BA1_UV(i));
518 SR(OVL_FIR2(i));
519 SR(OVL_ACCU2_0(i));
520 SR(OVL_ACCU2_1(i));
521
522 for (j = 0; j < 8; j++)
523 SR(OVL_FIR_COEF_H2(i, j));
524
525 for (j = 0; j < 8; j++)
526 SR(OVL_FIR_COEF_HV2(i, j));
527
528 for (j = 0; j < 8; j++)
529 SR(OVL_FIR_COEF_V2(i, j));
530 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300531 if (dispc_has_feature(FEAT_ATTR2))
Archit Tanejac6104b82011-08-05 19:06:02 +0530532 SR(OVL_ATTRIBUTES2(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000533 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200534
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300535 if (dispc_has_feature(FEAT_CORE_CLK_DIV))
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600536 SR(DIVISOR);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300537
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300538 dispc.ctx_valid = true;
539
Tomi Valkeinen9229b512014-02-14 09:37:09 +0200540 DSSDBG("context saved\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200541}
542
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300543static void dispc_restore_context(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200544{
Tomi Valkeinen9229b512014-02-14 09:37:09 +0200545 int i, j;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300546
547 DSSDBG("dispc_restore_context\n");
548
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300549 if (!dispc.ctx_valid)
550 return;
551
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200552 /*RR(IRQENABLE);*/
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200553 /*RR(CONTROL);*/
554 RR(CONFIG);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200555 RR(LINE_NUMBER);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300556 if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
557 dispc_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300558 RR(GLOBAL_ALPHA);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300559 if (dispc_has_feature(FEAT_MGR_LCD2))
Sumit Semwal2a205f32010-12-02 11:27:12 +0000560 RR(CONFIG2);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300561 if (dispc_has_feature(FEAT_MGR_LCD3))
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530562 RR(CONFIG3);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200563
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200564 for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530565 RR(DEFAULT_COLOR(i));
566 RR(TRANS_COLOR(i));
567 RR(SIZE_MGR(i));
568 if (i == OMAP_DSS_CHANNEL_DIGIT)
569 continue;
570 RR(TIMING_H(i));
571 RR(TIMING_V(i));
572 RR(POL_FREQ(i));
573 RR(DIVISORo(i));
Archit Taneja9b372c22011-05-06 11:45:49 +0530574
Archit Tanejac6104b82011-08-05 19:06:02 +0530575 RR(DATA_CYCLE1(i));
576 RR(DATA_CYCLE2(i));
577 RR(DATA_CYCLE3(i));
Sumit Semwal2a205f32010-12-02 11:27:12 +0000578
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300579 if (dispc_has_feature(FEAT_CPR)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530580 RR(CPR_COEF_R(i));
581 RR(CPR_COEF_G(i));
582 RR(CPR_COEF_B(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300583 }
Sumit Semwal2a205f32010-12-02 11:27:12 +0000584 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200585
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200586 for (i = 0; i < dispc_get_num_ovls(&dispc); i++) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530587 RR(OVL_BA0(i));
588 RR(OVL_BA1(i));
589 RR(OVL_POSITION(i));
590 RR(OVL_SIZE(i));
591 RR(OVL_ATTRIBUTES(i));
592 RR(OVL_FIFO_THRESHOLD(i));
593 RR(OVL_ROW_INC(i));
594 RR(OVL_PIXEL_INC(i));
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300595 if (dispc_has_feature(FEAT_PRELOAD))
Archit Tanejac6104b82011-08-05 19:06:02 +0530596 RR(OVL_PRELOAD(i));
597 if (i == OMAP_DSS_GFX) {
598 RR(OVL_WINDOW_SKIP(i));
599 RR(OVL_TABLE_BA(i));
600 continue;
601 }
602 RR(OVL_FIR(i));
603 RR(OVL_PICTURE_SIZE(i));
604 RR(OVL_ACCU0(i));
605 RR(OVL_ACCU1(i));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200606
Archit Tanejac6104b82011-08-05 19:06:02 +0530607 for (j = 0; j < 8; j++)
608 RR(OVL_FIR_COEF_H(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200609
Archit Tanejac6104b82011-08-05 19:06:02 +0530610 for (j = 0; j < 8; j++)
611 RR(OVL_FIR_COEF_HV(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200612
Archit Tanejac6104b82011-08-05 19:06:02 +0530613 for (j = 0; j < 5; j++)
614 RR(OVL_CONV_COEF(i, j));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200615
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300616 if (dispc_has_feature(FEAT_FIR_COEF_V)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530617 for (j = 0; j < 8; j++)
618 RR(OVL_FIR_COEF_V(i, j));
619 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200620
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300621 if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
Archit Tanejac6104b82011-08-05 19:06:02 +0530622 RR(OVL_BA0_UV(i));
623 RR(OVL_BA1_UV(i));
624 RR(OVL_FIR2(i));
625 RR(OVL_ACCU2_0(i));
626 RR(OVL_ACCU2_1(i));
627
628 for (j = 0; j < 8; j++)
629 RR(OVL_FIR_COEF_H2(i, j));
630
631 for (j = 0; j < 8; j++)
632 RR(OVL_FIR_COEF_HV2(i, j));
633
634 for (j = 0; j < 8; j++)
635 RR(OVL_FIR_COEF_V2(i, j));
636 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300637 if (dispc_has_feature(FEAT_ATTR2))
Archit Tanejac6104b82011-08-05 19:06:02 +0530638 RR(OVL_ATTRIBUTES2(i));
Tomi Valkeinen332e9d72011-05-27 14:22:16 +0300639 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200640
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300641 if (dispc_has_feature(FEAT_CORE_CLK_DIV))
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -0600642 RR(DIVISOR);
643
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200644 /* enable last, because LCD & DIGIT enable are here */
645 RR(CONTROL);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300646 if (dispc_has_feature(FEAT_MGR_LCD2))
Sumit Semwal2a205f32010-12-02 11:27:12 +0000647 RR(CONTROL2);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300648 if (dispc_has_feature(FEAT_MGR_LCD3))
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +0530649 RR(CONTROL3);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200650 /* clear spurious SYNC_LOST_DIGIT interrupts */
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200651 dispc_clear_irqstatus(&dispc, DISPC_IRQ_SYNC_LOST_DIGIT);
Ville Syrjälä75c7d592010-03-05 01:13:11 +0200652
653 /*
654 * enable last so IRQs won't trigger before
655 * the context is fully restored
656 */
657 RR(IRQENABLE);
Tomi Valkeinen49ea86f2011-06-01 15:54:06 +0300658
659 DSSDBG("context restored\n");
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200660}
661
662#undef SR
663#undef RR
664
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200665int dispc_runtime_get(struct dispc_device *dispc)
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300666{
667 int r;
668
669 DSSDBG("dispc_runtime_get\n");
670
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200671 r = pm_runtime_get_sync(&dispc->pdev->dev);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300672 WARN_ON(r < 0);
673 return r < 0 ? r : 0;
674}
675
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200676void dispc_runtime_put(struct dispc_device *dispc)
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300677{
678 int r;
679
680 DSSDBG("dispc_runtime_put\n");
681
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200682 r = pm_runtime_put_sync(&dispc->pdev->dev);
Tomi Valkeinen5be3aeb2012-06-27 16:37:18 +0300683 WARN_ON(r < 0 && r != -ENOSYS);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +0300684}
685
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200686static u32 dispc_mgr_get_vsync_irq(struct dispc_device *dispc,
687 enum omap_channel channel)
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200688{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530689 return mgr_desc[channel].vsync_irq;
Tomi Valkeinen3dcec4d2011-11-07 15:50:09 +0200690}
691
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200692static u32 dispc_mgr_get_framedone_irq(struct dispc_device *dispc,
693 enum omap_channel channel)
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200694{
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200695 if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc->feat->no_framedone_tv)
Tomi Valkeinencffa9472012-11-08 10:01:33 +0200696 return 0;
697
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530698 return mgr_desc[channel].framedone_irq;
Tomi Valkeinen7d1365c2011-11-18 15:39:52 +0200699}
700
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200701static u32 dispc_mgr_get_sync_lost_irq(struct dispc_device *dispc,
702 enum omap_channel channel)
Tomi Valkeinencb699202012-10-17 10:38:52 +0300703{
704 return mgr_desc[channel].sync_lost_irq;
705}
706
Laurent Pinchart8a7eda72018-02-13 14:00:43 +0200707u32 dispc_wb_get_framedone_irq(struct dispc_device *dispc)
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530708{
709 return DISPC_IRQ_FRAMEDONEWB;
710}
711
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200712static void dispc_mgr_enable(struct dispc_device *dispc,
713 enum omap_channel channel, bool enable)
Laurent Pinchart03af8152016-04-18 03:09:48 +0300714{
715 mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable);
716 /* flush posted write */
717 mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
718}
Laurent Pinchart03af8152016-04-18 03:09:48 +0300719
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200720static bool dispc_mgr_is_enabled(struct dispc_device *dispc,
721 enum omap_channel channel)
Laurent Pinchart03af8152016-04-18 03:09:48 +0300722{
723 return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE);
724}
725
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200726static bool dispc_mgr_go_busy(struct dispc_device *dispc,
727 enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200728{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530729 return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200730}
731
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200732static void dispc_mgr_go(struct dispc_device *dispc, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200733{
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200734 WARN_ON(!dispc_mgr_is_enabled(dispc, channel));
735 WARN_ON(dispc_mgr_go_busy(dispc, channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200736
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530737 DSSDBG("GO %s\n", mgr_desc[channel].name);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200738
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +0530739 mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200740}
741
Laurent Pinchart8a7eda72018-02-13 14:00:43 +0200742bool dispc_wb_go_busy(struct dispc_device *dispc)
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530743{
744 return REG_GET(DISPC_CONTROL2, 6, 6) == 1;
745}
746
Laurent Pinchart8a7eda72018-02-13 14:00:43 +0200747void dispc_wb_go(struct dispc_device *dispc)
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530748{
Jyri Sarha864050c2017-03-24 16:47:52 +0200749 enum omap_plane_id plane = OMAP_DSS_WB;
Archit Taneja0b23e5b2012-09-22 12:39:33 +0530750 bool enable, go;
751
752 enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1;
753
754 if (!enable)
755 return;
756
757 go = REG_GET(DISPC_CONTROL2, 6, 6) == 1;
758 if (go) {
759 DSSERR("GO bit not down for WB\n");
760 return;
761 }
762
763 REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6);
764}
765
Jyri Sarha864050c2017-03-24 16:47:52 +0200766static void dispc_ovl_write_firh_reg(enum omap_plane_id plane, int reg,
767 u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200768{
Archit Taneja9b372c22011-05-06 11:45:49 +0530769 dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200770}
771
Jyri Sarha864050c2017-03-24 16:47:52 +0200772static void dispc_ovl_write_firhv_reg(enum omap_plane_id plane, int reg,
773 u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200774{
Archit Taneja9b372c22011-05-06 11:45:49 +0530775 dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200776}
777
Jyri Sarha864050c2017-03-24 16:47:52 +0200778static void dispc_ovl_write_firv_reg(enum omap_plane_id plane, int reg,
779 u32 value)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200780{
Archit Taneja9b372c22011-05-06 11:45:49 +0530781 dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200782}
783
Jyri Sarha864050c2017-03-24 16:47:52 +0200784static void dispc_ovl_write_firh2_reg(enum omap_plane_id plane, int reg,
785 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530786{
787 BUG_ON(plane == OMAP_DSS_GFX);
788
789 dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value);
790}
791
Jyri Sarha864050c2017-03-24 16:47:52 +0200792static void dispc_ovl_write_firhv2_reg(enum omap_plane_id plane, int reg,
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300793 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530794{
795 BUG_ON(plane == OMAP_DSS_GFX);
796
797 dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value);
798}
799
Jyri Sarha864050c2017-03-24 16:47:52 +0200800static void dispc_ovl_write_firv2_reg(enum omap_plane_id plane, int reg,
801 u32 value)
Amber Jainab5ca072011-05-19 19:47:53 +0530802{
803 BUG_ON(plane == OMAP_DSS_GFX);
804
805 dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value);
806}
807
Jyri Sarha864050c2017-03-24 16:47:52 +0200808static void dispc_ovl_set_scale_coef(enum omap_plane_id plane, int fir_hinc,
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530809 int fir_vinc, int five_taps,
810 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200811{
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530812 const struct dispc_coef *h_coef, *v_coef;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200813 int i;
814
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530815 h_coef = dispc_ovl_get_scale_coef(fir_hinc, true);
816 v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200817
818 for (i = 0; i < 8; i++) {
819 u32 h, hv;
820
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530821 h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0)
822 | FLD_VAL(h_coef[i].hc1_vc0, 15, 8)
823 | FLD_VAL(h_coef[i].hc2_vc1, 23, 16)
824 | FLD_VAL(h_coef[i].hc3_vc2, 31, 24);
825 hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0)
826 | FLD_VAL(v_coef[i].hc1_vc0, 15, 8)
827 | FLD_VAL(v_coef[i].hc2_vc1, 23, 16)
828 | FLD_VAL(v_coef[i].hc3_vc2, 31, 24);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200829
Amber Jain0d66cbb2011-05-19 19:47:54 +0530830 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300831 dispc_ovl_write_firh_reg(plane, i, h);
832 dispc_ovl_write_firhv_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530833 } else {
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300834 dispc_ovl_write_firh2_reg(plane, i, h);
835 dispc_ovl_write_firhv2_reg(plane, i, hv);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530836 }
837
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200838 }
839
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200840 if (five_taps) {
841 for (i = 0; i < 8; i++) {
842 u32 v;
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +0530843 v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0)
844 | FLD_VAL(v_coef[i].hc4_vc22, 15, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530845 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300846 dispc_ovl_write_firv_reg(plane, i, v);
Amber Jain0d66cbb2011-05-19 19:47:54 +0530847 else
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +0300848 dispc_ovl_write_firv2_reg(plane, i, v);
Grazvydas Ignotas66be8f62010-08-24 15:18:43 +0200849 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200850 }
851}
852
Archit Taneja6e5264b2012-09-11 12:04:47 +0530853
Jyri Sarha864050c2017-03-24 16:47:52 +0200854static void dispc_ovl_write_color_conv_coef(enum omap_plane_id plane,
Archit Taneja6e5264b2012-09-11 12:04:47 +0530855 const struct color_conv_coef *ct)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200856{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200857#define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0))
858
Archit Taneja6e5264b2012-09-11 12:04:47 +0530859 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry));
860 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb));
861 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr));
862 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by));
863 dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb));
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200864
Archit Taneja6e5264b2012-09-11 12:04:47 +0530865 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200866
867#undef CVAL
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200868}
869
Archit Taneja6e5264b2012-09-11 12:04:47 +0530870static void dispc_setup_color_conv_coef(void)
871{
872 int i;
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200873 int num_ovl = dispc_get_num_ovls(&dispc);
Archit Taneja6e5264b2012-09-11 12:04:47 +0530874 const struct color_conv_coef ctbl_bt601_5_ovl = {
Tomi Valkeinen7d18bbe2015-11-04 17:10:52 +0200875 /* YUV -> RGB */
Archit Taneja6e5264b2012-09-11 12:04:47 +0530876 298, 409, 0, 298, -208, -100, 298, 0, 517, 0,
877 };
878 const struct color_conv_coef ctbl_bt601_5_wb = {
Tomi Valkeinen7d18bbe2015-11-04 17:10:52 +0200879 /* RGB -> YUV */
880 66, 129, 25, 112, -94, -18, -38, -74, 112, 0,
Archit Taneja6e5264b2012-09-11 12:04:47 +0530881 };
882
883 for (i = 1; i < num_ovl; i++)
884 dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl);
885
Tomi Valkeinen20efbc32015-11-04 17:10:44 +0200886 if (dispc.feat->has_writeback)
887 dispc_ovl_write_color_conv_coef(OMAP_DSS_WB, &ctbl_bt601_5_wb);
Archit Taneja6e5264b2012-09-11 12:04:47 +0530888}
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200889
Jyri Sarha864050c2017-03-24 16:47:52 +0200890static void dispc_ovl_set_ba0(enum omap_plane_id plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200891{
Archit Taneja9b372c22011-05-06 11:45:49 +0530892 dispc_write_reg(DISPC_OVL_BA0(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200893}
894
Jyri Sarha864050c2017-03-24 16:47:52 +0200895static void dispc_ovl_set_ba1(enum omap_plane_id plane, u32 paddr)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200896{
Archit Taneja9b372c22011-05-06 11:45:49 +0530897 dispc_write_reg(DISPC_OVL_BA1(plane), paddr);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200898}
899
Jyri Sarha864050c2017-03-24 16:47:52 +0200900static void dispc_ovl_set_ba0_uv(enum omap_plane_id plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530901{
902 dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr);
903}
904
Jyri Sarha864050c2017-03-24 16:47:52 +0200905static void dispc_ovl_set_ba1_uv(enum omap_plane_id plane, u32 paddr)
Amber Jainab5ca072011-05-19 19:47:53 +0530906{
907 dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr);
908}
909
Jyri Sarha864050c2017-03-24 16:47:52 +0200910static void dispc_ovl_set_pos(enum omap_plane_id plane,
Archit Tanejad79db852012-09-22 12:30:17 +0530911 enum omap_overlay_caps caps, int x, int y)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200912{
Archit Tanejad79db852012-09-22 12:30:17 +0530913 u32 val;
914
915 if ((caps & OMAP_DSS_OVL_CAP_POS) == 0)
916 return;
917
918 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530919
920 dispc_write_reg(DISPC_OVL_POSITION(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200921}
922
Jyri Sarha864050c2017-03-24 16:47:52 +0200923static void dispc_ovl_set_input_size(enum omap_plane_id plane, int width,
Archit Taneja78b687f2012-09-21 14:51:49 +0530924 int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200925{
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200926 u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530927
Archit Taneja36d87d92012-07-28 22:59:03 +0530928 if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB)
Archit Taneja9b372c22011-05-06 11:45:49 +0530929 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
930 else
931 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200932}
933
Jyri Sarha864050c2017-03-24 16:47:52 +0200934static void dispc_ovl_set_output_size(enum omap_plane_id plane, int width,
Archit Taneja78b687f2012-09-21 14:51:49 +0530935 int height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200936{
937 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200938
939 BUG_ON(plane == OMAP_DSS_GFX);
940
941 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0);
Archit Taneja9b372c22011-05-06 11:45:49 +0530942
Archit Taneja36d87d92012-07-28 22:59:03 +0530943 if (plane == OMAP_DSS_WB)
944 dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val);
945 else
946 dispc_write_reg(DISPC_OVL_SIZE(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200947}
948
Jyri Sarha864050c2017-03-24 16:47:52 +0200949static void dispc_ovl_set_zorder(enum omap_plane_id plane,
Archit Taneja5b54ed32012-09-26 16:55:27 +0530950 enum omap_overlay_caps caps, u8 zorder)
Archit Taneja54128702011-09-08 11:29:17 +0530951{
Archit Taneja5b54ed32012-09-26 16:55:27 +0530952 if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0)
Archit Taneja54128702011-09-08 11:29:17 +0530953 return;
954
955 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26);
956}
957
958static void dispc_ovl_enable_zorder_planes(void)
959{
960 int i;
961
Laurent Pinchart1ac0c892017-08-05 01:44:14 +0300962 if (!dispc_has_feature(FEAT_ALPHA_FREE_ZORDER))
Archit Taneja54128702011-09-08 11:29:17 +0530963 return;
964
Laurent Pinchart50638ae2018-02-13 14:00:42 +0200965 for (i = 0; i < dispc_get_num_ovls(&dispc); i++)
Archit Taneja54128702011-09-08 11:29:17 +0530966 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25);
967}
968
Jyri Sarha864050c2017-03-24 16:47:52 +0200969static void dispc_ovl_set_pre_mult_alpha(enum omap_plane_id plane,
Archit Taneja5b54ed32012-09-26 16:55:27 +0530970 enum omap_overlay_caps caps, bool enable)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100971{
Archit Taneja5b54ed32012-09-26 16:55:27 +0530972 if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100973 return;
974
Archit Taneja9b372c22011-05-06 11:45:49 +0530975 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28);
Rajkumar Nfd28a392010-11-04 12:28:42 +0100976}
977
Jyri Sarha864050c2017-03-24 16:47:52 +0200978static void dispc_ovl_setup_global_alpha(enum omap_plane_id plane,
Archit Taneja5b54ed32012-09-26 16:55:27 +0530979 enum omap_overlay_caps caps, u8 global_alpha)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200980{
Laurent Pinchartd11e5c82018-02-11 15:07:34 +0200981 static const unsigned int shifts[] = { 0, 8, 16, 24, };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300982 int shift;
983
Archit Taneja5b54ed32012-09-26 16:55:27 +0530984 if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0)
Rajkumar Nfd28a392010-11-04 12:28:42 +0100985 return;
Archit Tanejaa0acb552010-09-15 19:20:00 +0530986
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +0300987 shift = shifts[plane];
988 REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200989}
990
Jyri Sarha864050c2017-03-24 16:47:52 +0200991static void dispc_ovl_set_pix_inc(enum omap_plane_id plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200992{
Archit Taneja9b372c22011-05-06 11:45:49 +0530993 dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200994}
995
Jyri Sarha864050c2017-03-24 16:47:52 +0200996static void dispc_ovl_set_row_inc(enum omap_plane_id plane, s32 inc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200997{
Archit Taneja9b372c22011-05-06 11:45:49 +0530998 dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +0200999}
1000
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001001static void dispc_ovl_set_color_mode(enum omap_plane_id plane, u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001002{
1003 u32 m = 0;
Amber Jainf20e4222011-05-19 19:47:50 +05301004 if (plane != OMAP_DSS_GFX) {
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001005 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001006 case DRM_FORMAT_NV12:
Amber Jainf20e4222011-05-19 19:47:50 +05301007 m = 0x0; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001008 case DRM_FORMAT_XRGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301009 m = 0x1; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001010 case DRM_FORMAT_RGBA4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301011 m = 0x2; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001012 case DRM_FORMAT_RGBX4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301013 m = 0x4; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001014 case DRM_FORMAT_ARGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301015 m = 0x5; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001016 case DRM_FORMAT_RGB565:
Amber Jainf20e4222011-05-19 19:47:50 +05301017 m = 0x6; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001018 case DRM_FORMAT_ARGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +05301019 m = 0x7; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001020 case DRM_FORMAT_XRGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301021 m = 0x8; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001022 case DRM_FORMAT_RGB888:
Amber Jainf20e4222011-05-19 19:47:50 +05301023 m = 0x9; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001024 case DRM_FORMAT_YUYV:
Amber Jainf20e4222011-05-19 19:47:50 +05301025 m = 0xa; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001026 case DRM_FORMAT_UYVY:
Amber Jainf20e4222011-05-19 19:47:50 +05301027 m = 0xb; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001028 case DRM_FORMAT_ARGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301029 m = 0xc; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001030 case DRM_FORMAT_RGBA8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301031 m = 0xd; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001032 case DRM_FORMAT_RGBX8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301033 m = 0xe; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001034 case DRM_FORMAT_XRGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +05301035 m = 0xf; break;
1036 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001037 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +05301038 }
1039 } else {
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001040 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001041 case DRM_FORMAT_RGBX4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301042 m = 0x4; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001043 case DRM_FORMAT_ARGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301044 m = 0x5; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001045 case DRM_FORMAT_RGB565:
Amber Jainf20e4222011-05-19 19:47:50 +05301046 m = 0x6; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001047 case DRM_FORMAT_ARGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +05301048 m = 0x7; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001049 case DRM_FORMAT_XRGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301050 m = 0x8; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001051 case DRM_FORMAT_RGB888:
Amber Jainf20e4222011-05-19 19:47:50 +05301052 m = 0x9; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001053 case DRM_FORMAT_XRGB4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301054 m = 0xa; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001055 case DRM_FORMAT_RGBA4444:
Amber Jainf20e4222011-05-19 19:47:50 +05301056 m = 0xb; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001057 case DRM_FORMAT_ARGB8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301058 m = 0xc; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001059 case DRM_FORMAT_RGBA8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301060 m = 0xd; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001061 case DRM_FORMAT_RGBX8888:
Amber Jainf20e4222011-05-19 19:47:50 +05301062 m = 0xe; break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001063 case DRM_FORMAT_XRGB1555:
Amber Jainf20e4222011-05-19 19:47:50 +05301064 m = 0xf; break;
1065 default:
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001066 BUG(); return;
Amber Jainf20e4222011-05-19 19:47:50 +05301067 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001068 }
1069
Archit Taneja9b372c22011-05-06 11:45:49 +05301070 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001071}
1072
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001073static bool format_is_yuv(u32 fourcc)
Tomi Valkeinen5edec142017-05-04 09:13:32 +03001074{
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001075 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001076 case DRM_FORMAT_YUYV:
1077 case DRM_FORMAT_UYVY:
1078 case DRM_FORMAT_NV12:
Tomi Valkeinen5edec142017-05-04 09:13:32 +03001079 return true;
1080 default:
1081 return false;
1082 }
1083}
1084
Jyri Sarha864050c2017-03-24 16:47:52 +02001085static void dispc_ovl_configure_burst_type(enum omap_plane_id plane,
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301086 enum omap_dss_rotation_type rotation_type)
1087{
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001088 if (dispc_has_feature(FEAT_BURST_2D) == 0)
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05301089 return;
1090
1091 if (rotation_type == OMAP_DSS_ROT_TILER)
1092 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29);
1093 else
1094 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29);
1095}
1096
Jyri Sarha864050c2017-03-24 16:47:52 +02001097static void dispc_ovl_set_channel_out(enum omap_plane_id plane,
1098 enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001099{
1100 int shift;
1101 u32 val;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001102 int chan = 0, chan2 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001103
1104 switch (plane) {
1105 case OMAP_DSS_GFX:
1106 shift = 8;
1107 break;
1108 case OMAP_DSS_VIDEO1:
1109 case OMAP_DSS_VIDEO2:
Archit Tanejab8c095b2011-09-13 18:20:33 +05301110 case OMAP_DSS_VIDEO3:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001111 shift = 16;
1112 break;
1113 default:
1114 BUG();
1115 return;
1116 }
1117
Archit Taneja9b372c22011-05-06 11:45:49 +05301118 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001119 if (dispc_has_feature(FEAT_MGR_LCD2)) {
Sumit Semwal2a205f32010-12-02 11:27:12 +00001120 switch (channel) {
1121 case OMAP_DSS_CHANNEL_LCD:
1122 chan = 0;
1123 chan2 = 0;
1124 break;
1125 case OMAP_DSS_CHANNEL_DIGIT:
1126 chan = 1;
1127 chan2 = 0;
1128 break;
1129 case OMAP_DSS_CHANNEL_LCD2:
1130 chan = 0;
1131 chan2 = 1;
1132 break;
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +05301133 case OMAP_DSS_CHANNEL_LCD3:
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001134 if (dispc_has_feature(FEAT_MGR_LCD3)) {
Chandrabhanu Mahapatrae86d4562012-06-29 10:43:13 +05301135 chan = 0;
1136 chan2 = 2;
1137 } else {
1138 BUG();
1139 return;
1140 }
1141 break;
Tomi Valkeinenc2665c42015-11-04 17:10:47 +02001142 case OMAP_DSS_CHANNEL_WB:
1143 chan = 0;
1144 chan2 = 3;
1145 break;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001146 default:
1147 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001148 return;
Sumit Semwal2a205f32010-12-02 11:27:12 +00001149 }
1150
1151 val = FLD_MOD(val, chan, shift, shift);
1152 val = FLD_MOD(val, chan2, 31, 30);
1153 } else {
1154 val = FLD_MOD(val, channel, shift, shift);
1155 }
Archit Taneja9b372c22011-05-06 11:45:49 +05301156 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001157}
1158
Jyri Sarha864050c2017-03-24 16:47:52 +02001159static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane_id plane)
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001160{
1161 int shift;
1162 u32 val;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001163
1164 switch (plane) {
1165 case OMAP_DSS_GFX:
1166 shift = 8;
1167 break;
1168 case OMAP_DSS_VIDEO1:
1169 case OMAP_DSS_VIDEO2:
1170 case OMAP_DSS_VIDEO3:
1171 shift = 16;
1172 break;
1173 default:
1174 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001175 return 0;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001176 }
1177
1178 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
1179
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001180 if (FLD_GET(val, shift, shift) == 1)
1181 return OMAP_DSS_CHANNEL_DIGIT;
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001182
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001183 if (!dispc_has_feature(FEAT_MGR_LCD2))
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001184 return OMAP_DSS_CHANNEL_LCD;
1185
1186 switch (FLD_GET(val, 31, 30)) {
1187 case 0:
1188 default:
1189 return OMAP_DSS_CHANNEL_LCD;
1190 case 1:
1191 return OMAP_DSS_CHANNEL_LCD2;
1192 case 2:
1193 return OMAP_DSS_CHANNEL_LCD3;
Tomi Valkeinenc2665c42015-11-04 17:10:47 +02001194 case 3:
1195 return OMAP_DSS_CHANNEL_WB;
Tomi Valkeinend7df5ad2015-11-04 17:10:46 +02001196 }
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02001197}
1198
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001199void dispc_wb_set_channel_in(struct dispc_device *dispc,
1200 enum dss_writeback_channel channel)
Archit Tanejad9ac7732012-09-22 12:38:19 +05301201{
Jyri Sarha864050c2017-03-24 16:47:52 +02001202 enum omap_plane_id plane = OMAP_DSS_WB;
Archit Tanejad9ac7732012-09-22 12:38:19 +05301203
1204 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16);
1205}
1206
Jyri Sarha864050c2017-03-24 16:47:52 +02001207static void dispc_ovl_set_burst_size(enum omap_plane_id plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001208 enum omap_burst_size burst_size)
1209{
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02001210 static const unsigned int shifts[] = { 6, 14, 14, 14, 14, };
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001211 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001212
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001213 shift = shifts[plane];
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001214 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001215}
1216
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001217static void dispc_configure_burst_sizes(void)
1218{
1219 int i;
1220 const int burst_size = BURST_SIZE_X8;
1221
1222 /* Configure burst size always to maximum size */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02001223 for (i = 0; i < dispc_get_num_ovls(&dispc); ++i)
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001224 dispc_ovl_set_burst_size(i, burst_size);
Tomi Valkeinen5b354af2015-11-04 17:10:48 +02001225 if (dispc.feat->has_writeback)
1226 dispc_ovl_set_burst_size(OMAP_DSS_WB, burst_size);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001227}
1228
Jyri Sarha864050c2017-03-24 16:47:52 +02001229static u32 dispc_ovl_get_burst_size(enum omap_plane_id plane)
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001230{
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001231 /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */
Laurent Pinchart28550472017-08-05 01:44:03 +03001232 return dispc.feat->burst_size_unit * 8;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001233}
1234
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03001235static bool dispc_ovl_color_mode_supported(enum omap_plane_id plane, u32 fourcc)
1236{
1237 const u32 *modes;
1238 unsigned int i;
1239
1240 modes = dispc.feat->supported_color_modes[plane];
1241
1242 for (i = 0; modes[i]; ++i) {
1243 if (modes[i] == fourcc)
1244 return true;
1245 }
1246
1247 return false;
1248}
1249
Laurent Pinchart50638ae2018-02-13 14:00:42 +02001250static const u32 *dispc_ovl_get_color_modes(struct dispc_device *dispc,
1251 enum omap_plane_id plane)
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001252{
Laurent Pinchart50638ae2018-02-13 14:00:42 +02001253 return dispc->feat->supported_color_modes[plane];
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001254}
Tomi Valkeinenc2834002015-11-05 19:54:33 +02001255
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001256static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001257{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301258 if (channel == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001259 return;
1260
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05301261 mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable);
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001262}
1263
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02001264static void dispc_mgr_set_cpr_coef(enum omap_channel channel,
Tomi Valkeinena8f3fcd2012-10-03 09:09:11 +02001265 const struct omap_dss_cpr_coefs *coefs)
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001266{
1267 u32 coef_r, coef_g, coef_b;
1268
Archit Tanejadd88b7a2012-06-29 14:41:30 +05301269 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinen3c07cae2011-06-21 09:34:30 +03001270 return;
1271
1272 coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) |
1273 FLD_VAL(coefs->rb, 9, 0);
1274 coef_g = FLD_VAL(coefs->gr, 31, 22) | FLD_VAL(coefs->gg, 20, 11) |
1275 FLD_VAL(coefs->gb, 9, 0);
1276 coef_b = FLD_VAL(coefs->br, 31, 22) | FLD_VAL(coefs->bg, 20, 11) |
1277 FLD_VAL(coefs->bb, 9, 0);
1278
1279 dispc_write_reg(DISPC_CPR_COEF_R(channel), coef_r);
1280 dispc_write_reg(DISPC_CPR_COEF_G(channel), coef_g);
1281 dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b);
1282}
1283
Jyri Sarha864050c2017-03-24 16:47:52 +02001284static void dispc_ovl_set_vid_color_conv(enum omap_plane_id plane,
1285 bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001286{
1287 u32 val;
1288
1289 BUG_ON(plane == OMAP_DSS_GFX);
1290
Archit Taneja9b372c22011-05-06 11:45:49 +05301291 val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001292 val = FLD_MOD(val, enable, 9, 9);
Archit Taneja9b372c22011-05-06 11:45:49 +05301293 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001294}
1295
Jyri Sarha864050c2017-03-24 16:47:52 +02001296static void dispc_ovl_enable_replication(enum omap_plane_id plane,
Archit Tanejad79db852012-09-22 12:30:17 +05301297 enum omap_overlay_caps caps, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001298{
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02001299 static const unsigned int shifts[] = { 5, 10, 10, 10 };
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001300 int shift;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001301
Archit Tanejad79db852012-09-22 12:30:17 +05301302 if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0)
1303 return;
1304
Tomi Valkeinenfe3cc9d2011-08-15 11:51:50 +03001305 shift = shifts[plane];
1306 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001307}
1308
Archit Taneja8f366162012-04-16 12:53:44 +05301309static void dispc_mgr_set_size(enum omap_channel channel, u16 width,
Archit Tanejae5c09e02012-04-16 12:53:42 +05301310 u16 height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001311{
1312 u32 val;
Archit Taneja8f366162012-04-16 12:53:44 +05301313
Archit Taneja33b89922012-11-14 13:50:15 +05301314 val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) |
1315 FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0);
1316
Archit Taneja702d1442011-05-06 11:45:50 +05301317 dispc_write_reg(DISPC_SIZE_MGR(channel), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001318}
1319
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001320static void dispc_init_fifos(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001321{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001322 u32 size;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001323 int fifo;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301324 u8 start, end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001325 u32 unit;
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001326 int i;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001327
Laurent Pinchart28550472017-08-05 01:44:03 +03001328 unit = dispc.feat->buffer_size_unit;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001329
Laurent Pinchart38dc0702017-08-05 01:44:08 +03001330 dispc_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001331
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001332 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1333 size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end);
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001334 size *= unit;
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001335 dispc.fifo_size[fifo] = size;
1336
1337 /*
1338 * By default fifos are mapped directly to overlays, fifo 0 to
1339 * ovl 0, fifo 1 to ovl 1, etc.
1340 */
1341 dispc.fifo_assignment[fifo] = fifo;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001342 }
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +03001343
1344 /*
1345 * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo
1346 * causes problems with certain use cases, like using the tiler in 2D
1347 * mode. The below hack swaps the fifos of GFX and WB planes, thus
1348 * giving GFX plane a larger fifo. WB but should work fine with a
1349 * smaller fifo.
1350 */
1351 if (dispc.feat->gfx_fifo_workaround) {
1352 u32 v;
1353
1354 v = dispc_read_reg(DISPC_GLOBAL_BUFFER);
1355
1356 v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */
1357 v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */
1358 v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */
1359 v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */
1360
1361 dispc_write_reg(DISPC_GLOBAL_BUFFER, v);
1362
1363 dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB;
1364 dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX;
1365 }
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001366
1367 /*
1368 * Setup default fifo thresholds.
1369 */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02001370 for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) {
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001371 u32 low, high;
1372 const bool use_fifomerge = false;
1373 const bool manual_update = false;
1374
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001375 dispc_ovl_compute_fifo_thresholds(&dispc, i, &low, &high,
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001376 use_fifomerge, manual_update);
1377
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001378 dispc_ovl_set_fifo_threshold(&dispc, i, low, high);
Tomi Valkeinen47fc4692014-09-29 20:46:17 +00001379 }
Tomi Valkeinen65e116e2015-11-04 17:10:49 +02001380
1381 if (dispc.feat->has_writeback) {
1382 u32 low, high;
1383 const bool use_fifomerge = false;
1384 const bool manual_update = false;
1385
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001386 dispc_ovl_compute_fifo_thresholds(&dispc, OMAP_DSS_WB,
1387 &low, &high,
1388 use_fifomerge, manual_update);
Tomi Valkeinen65e116e2015-11-04 17:10:49 +02001389
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001390 dispc_ovl_set_fifo_threshold(&dispc, OMAP_DSS_WB, low, high);
Tomi Valkeinen65e116e2015-11-04 17:10:49 +02001391 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001392}
1393
Jyri Sarha864050c2017-03-24 16:47:52 +02001394static u32 dispc_ovl_get_fifo_size(enum omap_plane_id plane)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001395{
Tomi Valkeinen42a69612012-08-22 16:56:57 +03001396 int fifo;
1397 u32 size = 0;
1398
1399 for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) {
1400 if (dispc.fifo_assignment[fifo] == plane)
1401 size += dispc.fifo_size[fifo];
1402 }
1403
1404 return size;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001405}
1406
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001407void dispc_ovl_set_fifo_threshold(struct dispc_device *dispc,
1408 enum omap_plane_id plane,
1409 u32 low, u32 high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001410{
Archit Tanejaa0acb552010-09-15 19:20:00 +05301411 u8 hi_start, hi_end, lo_start, lo_end;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001412 u32 unit;
1413
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001414 unit = dispc->feat->buffer_size_unit;
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03001415
1416 WARN_ON(low % unit != 0);
1417 WARN_ON(high % unit != 0);
1418
1419 low /= unit;
1420 high /= unit;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301421
Laurent Pinchart38dc0702017-08-05 01:44:08 +03001422 dispc_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end);
1423 dispc_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end);
Archit Taneja9b372c22011-05-06 11:45:49 +05301424
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001425 DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n",
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001426 plane,
Archit Taneja9b372c22011-05-06 11:45:49 +05301427 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001428 lo_start, lo_end) * unit,
Archit Taneja9b372c22011-05-06 11:45:49 +05301429 REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane),
Tomi Valkeinen3cb5d962012-01-13 13:14:57 +02001430 hi_start, hi_end) * unit,
1431 low * unit, high * unit);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001432
Archit Taneja9b372c22011-05-06 11:45:49 +05301433 dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane),
Archit Tanejaa0acb552010-09-15 19:20:00 +05301434 FLD_VAL(high, hi_start, hi_end) |
1435 FLD_VAL(low, lo_start, lo_end));
Archit Taneja8bc65552013-12-17 16:40:21 +05301436
1437 /*
1438 * configure the preload to the pipeline's high threhold, if HT it's too
1439 * large for the preload field, set the threshold to the maximum value
1440 * that can be held by the preload register
1441 */
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001442 if (dispc_has_feature(FEAT_PRELOAD) && dispc->feat->set_max_preload &&
Archit Taneja8bc65552013-12-17 16:40:21 +05301443 plane != OMAP_DSS_WB)
1444 dispc_write_reg(DISPC_OVL_PRELOAD(plane), min(high, 0xfffu));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001445}
1446
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001447void dispc_enable_fifomerge(struct dispc_device *dispc, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001448{
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001449 if (!dispc_has_feature(FEAT_FIFO_MERGE)) {
Tomi Valkeinene6b0f882012-01-13 13:24:04 +02001450 WARN_ON(enable);
1451 return;
1452 }
1453
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001454 DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled");
1455 REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001456}
1457
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001458void dispc_ovl_compute_fifo_thresholds(struct dispc_device *dispc,
1459 enum omap_plane_id plane,
1460 u32 *fifo_low, u32 *fifo_high,
1461 bool use_fifomerge, bool manual_update)
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001462{
1463 /*
1464 * All sizes are in bytes. Both the buffer and burst are made of
1465 * buffer_units, and the fifo thresholds must be buffer_unit aligned.
1466 */
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001467 unsigned int buf_unit = dispc->feat->buffer_size_unit;
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02001468 unsigned int ovl_fifo_size, total_fifo_size, burst_size;
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001469 int i;
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001470
1471 burst_size = dispc_ovl_get_burst_size(plane);
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001472 ovl_fifo_size = dispc_ovl_get_fifo_size(plane);
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001473
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001474 if (use_fifomerge) {
1475 total_fifo_size = 0;
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02001476 for (i = 0; i < dispc_get_num_ovls(dispc); ++i)
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001477 total_fifo_size += dispc_ovl_get_fifo_size(i);
1478 } else {
1479 total_fifo_size = ovl_fifo_size;
1480 }
1481
1482 /*
1483 * We use the same low threshold for both fifomerge and non-fifomerge
1484 * cases, but for fifomerge we calculate the high threshold using the
1485 * combined fifo size
1486 */
1487
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001488 if (manual_update && dispc_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) {
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001489 *fifo_low = ovl_fifo_size - burst_size * 2;
1490 *fifo_high = total_fifo_size - burst_size;
Archit Taneja8bbe09e2012-09-10 17:31:39 +05301491 } else if (plane == OMAP_DSS_WB) {
1492 /*
1493 * Most optimal configuration for writeback is to push out data
1494 * to the interconnect the moment writeback pushes enough pixels
1495 * in the FIFO to form a burst
1496 */
1497 *fifo_low = 0;
1498 *fifo_high = burst_size;
Tomi Valkeinene0e405b2012-01-13 13:18:11 +02001499 } else {
1500 *fifo_low = ovl_fifo_size - burst_size;
1501 *fifo_high = total_fifo_size - buf_unit;
1502 }
Tomi Valkeinen83fa2f22012-01-13 13:17:01 +02001503}
1504
Jyri Sarha864050c2017-03-24 16:47:52 +02001505static void dispc_ovl_set_mflag(enum omap_plane_id plane, bool enable)
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001506{
1507 int bit;
1508
1509 if (plane == OMAP_DSS_GFX)
1510 bit = 14;
1511 else
1512 bit = 23;
1513
1514 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit);
1515}
1516
Jyri Sarha864050c2017-03-24 16:47:52 +02001517static void dispc_ovl_set_mflag_threshold(enum omap_plane_id plane,
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001518 int low, int high)
1519{
1520 dispc_write_reg(DISPC_OVL_MFLAG_THRESHOLD(plane),
1521 FLD_VAL(high, 31, 16) | FLD_VAL(low, 15, 0));
1522}
1523
1524static void dispc_init_mflag(void)
1525{
1526 int i;
1527
Tomi Valkeinenfe59e5c2014-11-19 12:50:16 +02001528 /*
1529 * HACK: NV12 color format and MFLAG seem to have problems working
1530 * together: using two displays, and having an NV12 overlay on one of
1531 * the displays will cause underflows/synclosts when MFLAG_CTRL=2.
1532 * Changing MFLAG thresholds and PRELOAD to certain values seem to
1533 * remove the errors, but there doesn't seem to be a clear logic on
1534 * which values work and which not.
1535 *
1536 * As a work-around, set force MFLAG to always on.
1537 */
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001538 dispc_write_reg(DISPC_GLOBAL_MFLAG_ATTRIBUTE,
Tomi Valkeinenfe59e5c2014-11-19 12:50:16 +02001539 (1 << 0) | /* MFLAG_CTRL = force always on */
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001540 (0 << 2)); /* MFLAG_START = disable */
1541
Laurent Pinchart50638ae2018-02-13 14:00:42 +02001542 for (i = 0; i < dispc_get_num_ovls(&dispc); ++i) {
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001543 u32 size = dispc_ovl_get_fifo_size(i);
Laurent Pinchart28550472017-08-05 01:44:03 +03001544 u32 unit = dispc.feat->buffer_size_unit;
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001545 u32 low, high;
1546
1547 dispc_ovl_set_mflag(i, true);
1548
1549 /*
1550 * Simulation team suggests below thesholds:
1551 * HT = fifosize * 5 / 8;
1552 * LT = fifosize * 4 / 8;
1553 */
1554
1555 low = size * 4 / 8 / unit;
1556 high = size * 5 / 8 / unit;
1557
1558 dispc_ovl_set_mflag_threshold(i, low, high);
1559 }
Tomi Valkeinenecb0b362015-11-04 17:10:50 +02001560
1561 if (dispc.feat->has_writeback) {
1562 u32 size = dispc_ovl_get_fifo_size(OMAP_DSS_WB);
Laurent Pinchart28550472017-08-05 01:44:03 +03001563 u32 unit = dispc.feat->buffer_size_unit;
Tomi Valkeinenecb0b362015-11-04 17:10:50 +02001564 u32 low, high;
1565
1566 dispc_ovl_set_mflag(OMAP_DSS_WB, true);
1567
1568 /*
1569 * Simulation team suggests below thesholds:
1570 * HT = fifosize * 5 / 8;
1571 * LT = fifosize * 4 / 8;
1572 */
1573
1574 low = size * 4 / 8 / unit;
1575 high = size * 5 / 8 / unit;
1576
1577 dispc_ovl_set_mflag_threshold(OMAP_DSS_WB, low, high);
1578 }
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00001579}
1580
Jyri Sarha864050c2017-03-24 16:47:52 +02001581static void dispc_ovl_set_fir(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301582 int hinc, int vinc,
1583 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001584{
1585 u32 val;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001586
Amber Jain0d66cbb2011-05-19 19:47:54 +05301587 if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) {
1588 u8 hinc_start, hinc_end, vinc_start, vinc_end;
Archit Tanejaa0acb552010-09-15 19:20:00 +05301589
Laurent Pinchart38dc0702017-08-05 01:44:08 +03001590 dispc_get_reg_field(FEAT_REG_FIRHINC, &hinc_start, &hinc_end);
1591 dispc_get_reg_field(FEAT_REG_FIRVINC, &vinc_start, &vinc_end);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301592 val = FLD_VAL(vinc, vinc_start, vinc_end) |
1593 FLD_VAL(hinc, hinc_start, hinc_end);
Archit Tanejaa0acb552010-09-15 19:20:00 +05301594
Amber Jain0d66cbb2011-05-19 19:47:54 +05301595 dispc_write_reg(DISPC_OVL_FIR(plane), val);
1596 } else {
1597 val = FLD_VAL(vinc, 28, 16) | FLD_VAL(hinc, 12, 0);
1598 dispc_write_reg(DISPC_OVL_FIR2(plane), val);
1599 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001600}
1601
Jyri Sarha864050c2017-03-24 16:47:52 +02001602static void dispc_ovl_set_vid_accu0(enum omap_plane_id plane, int haccu,
1603 int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001604{
1605 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301606 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001607
Laurent Pinchart38dc0702017-08-05 01:44:08 +03001608 dispc_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1609 dispc_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
Archit Taneja87a74842011-03-02 11:19:50 +05301610
1611 val = FLD_VAL(vaccu, vert_start, vert_end) |
1612 FLD_VAL(haccu, hor_start, hor_end);
1613
Archit Taneja9b372c22011-05-06 11:45:49 +05301614 dispc_write_reg(DISPC_OVL_ACCU0(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001615}
1616
Jyri Sarha864050c2017-03-24 16:47:52 +02001617static void dispc_ovl_set_vid_accu1(enum omap_plane_id plane, int haccu,
1618 int vaccu)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001619{
1620 u32 val;
Archit Taneja87a74842011-03-02 11:19:50 +05301621 u8 hor_start, hor_end, vert_start, vert_end;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001622
Laurent Pinchart38dc0702017-08-05 01:44:08 +03001623 dispc_get_reg_field(FEAT_REG_HORIZONTALACCU, &hor_start, &hor_end);
1624 dispc_get_reg_field(FEAT_REG_VERTICALACCU, &vert_start, &vert_end);
Archit Taneja87a74842011-03-02 11:19:50 +05301625
1626 val = FLD_VAL(vaccu, vert_start, vert_end) |
1627 FLD_VAL(haccu, hor_start, hor_end);
1628
Archit Taneja9b372c22011-05-06 11:45:49 +05301629 dispc_write_reg(DISPC_OVL_ACCU1(plane), val);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001630}
1631
Jyri Sarha864050c2017-03-24 16:47:52 +02001632static void dispc_ovl_set_vid_accu2_0(enum omap_plane_id plane, int haccu,
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001633 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301634{
1635 u32 val;
1636
1637 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1638 dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val);
1639}
1640
Jyri Sarha864050c2017-03-24 16:47:52 +02001641static void dispc_ovl_set_vid_accu2_1(enum omap_plane_id plane, int haccu,
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001642 int vaccu)
Amber Jainab5ca072011-05-19 19:47:53 +05301643{
1644 u32 val;
1645
1646 val = FLD_VAL(vaccu, 26, 16) | FLD_VAL(haccu, 10, 0);
1647 dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val);
1648}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001649
Jyri Sarha864050c2017-03-24 16:47:52 +02001650static void dispc_ovl_set_scale_param(enum omap_plane_id plane,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001651 u16 orig_width, u16 orig_height,
1652 u16 out_width, u16 out_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301653 bool five_taps, u8 rotation,
1654 enum omap_color_component color_comp)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001655{
Amber Jain0d66cbb2011-05-19 19:47:54 +05301656 int fir_hinc, fir_vinc;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001657
Amber Jained14a3c2011-05-19 19:47:51 +05301658 fir_hinc = 1024 * orig_width / out_width;
1659 fir_vinc = 1024 * orig_height / out_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001660
Chandrabhanu Mahapatradebd9072011-12-19 14:03:44 +05301661 dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps,
1662 color_comp);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001663 dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301664}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001665
Jyri Sarha864050c2017-03-24 16:47:52 +02001666static void dispc_ovl_set_accu_uv(enum omap_plane_id plane,
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301667 u16 orig_width, u16 orig_height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001668 bool ilace, u32 fourcc, u8 rotation)
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301669{
1670 int h_accu2_0, h_accu2_1;
1671 int v_accu2_0, v_accu2_1;
1672 int chroma_hinc, chroma_vinc;
1673 int idx;
1674
1675 struct accu {
1676 s8 h0_m, h0_n;
1677 s8 h1_m, h1_n;
1678 s8 v0_m, v0_n;
1679 s8 v1_m, v1_n;
1680 };
1681
1682 const struct accu *accu_table;
1683 const struct accu *accu_val;
1684
1685 static const struct accu accu_nv12[4] = {
1686 { 0, 1, 0, 1 , -1, 2, 0, 1 },
1687 { 1, 2, -3, 4 , 0, 1, 0, 1 },
1688 { -1, 1, 0, 1 , -1, 2, 0, 1 },
1689 { -1, 2, -1, 2 , -1, 1, 0, 1 },
1690 };
1691
1692 static const struct accu accu_nv12_ilace[4] = {
1693 { 0, 1, 0, 1 , -3, 4, -1, 4 },
1694 { -1, 4, -3, 4 , 0, 1, 0, 1 },
1695 { -1, 1, 0, 1 , -1, 4, -3, 4 },
1696 { -3, 4, -3, 4 , -1, 1, 0, 1 },
1697 };
1698
1699 static const struct accu accu_yuv[4] = {
1700 { 0, 1, 0, 1, 0, 1, 0, 1 },
1701 { 0, 1, 0, 1, 0, 1, 0, 1 },
1702 { -1, 1, 0, 1, 0, 1, 0, 1 },
1703 { 0, 1, 0, 1, -1, 1, 0, 1 },
1704 };
1705
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001706 /* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */
1707 switch (rotation & DRM_MODE_ROTATE_MASK) {
1708 default:
1709 case DRM_MODE_ROTATE_0:
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301710 idx = 0;
1711 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001712 case DRM_MODE_ROTATE_90:
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301713 idx = 3;
1714 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001715 case DRM_MODE_ROTATE_180:
1716 idx = 2;
1717 break;
1718 case DRM_MODE_ROTATE_270:
1719 idx = 1;
1720 break;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301721 }
1722
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001723 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001724 case DRM_FORMAT_NV12:
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301725 if (ilace)
1726 accu_table = accu_nv12_ilace;
1727 else
1728 accu_table = accu_nv12;
1729 break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001730 case DRM_FORMAT_YUYV:
1731 case DRM_FORMAT_UYVY:
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301732 accu_table = accu_yuv;
1733 break;
1734 default:
1735 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001736 return;
Chandrabhanu Mahapatra05dd0f52012-05-15 12:22:34 +05301737 }
1738
1739 accu_val = &accu_table[idx];
1740
1741 chroma_hinc = 1024 * orig_width / out_width;
1742 chroma_vinc = 1024 * orig_height / out_height;
1743
1744 h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024;
1745 h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024;
1746 v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024;
1747 v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024;
1748
1749 dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0);
1750 dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1);
1751}
1752
Jyri Sarha864050c2017-03-24 16:47:52 +02001753static void dispc_ovl_set_scaling_common(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301754 u16 orig_width, u16 orig_height,
1755 u16 out_width, u16 out_height,
1756 bool ilace, bool five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001757 bool fieldmode, u32 fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301758 u8 rotation)
1759{
1760 int accu0 = 0;
1761 int accu1 = 0;
1762 u32 l;
1763
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001764 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301765 out_width, out_height, five_taps,
1766 rotation, DISPC_COLOR_COMPONENT_RGB_Y);
Archit Taneja9b372c22011-05-06 11:45:49 +05301767 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001768
Archit Taneja87a74842011-03-02 11:19:50 +05301769 /* RESIZEENABLE and VERTICALTAPS */
1770 l &= ~((0x3 << 5) | (0x1 << 21));
Amber Jained14a3c2011-05-19 19:47:51 +05301771 l |= (orig_width != out_width) ? (1 << 5) : 0;
1772 l |= (orig_height != out_height) ? (1 << 6) : 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001773 l |= five_taps ? (1 << 21) : 0;
Archit Taneja87a74842011-03-02 11:19:50 +05301774
1775 /* VRESIZECONF and HRESIZECONF */
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001776 if (dispc_has_feature(FEAT_RESIZECONF)) {
Archit Taneja87a74842011-03-02 11:19:50 +05301777 l &= ~(0x3 << 7);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301778 l |= (orig_width <= out_width) ? 0 : (1 << 7);
1779 l |= (orig_height <= out_height) ? 0 : (1 << 8);
Archit Taneja87a74842011-03-02 11:19:50 +05301780 }
1781
1782 /* LINEBUFFERSPLIT */
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001783 if (dispc_has_feature(FEAT_LINEBUFFERSPLIT)) {
Archit Taneja87a74842011-03-02 11:19:50 +05301784 l &= ~(0x1 << 22);
1785 l |= five_taps ? (1 << 22) : 0;
1786 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001787
Archit Taneja9b372c22011-05-06 11:45:49 +05301788 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001789
1790 /*
1791 * field 0 = even field = bottom field
1792 * field 1 = odd field = top field
1793 */
1794 if (ilace && !fieldmode) {
1795 accu1 = 0;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301796 accu0 = ((1024 * orig_height / out_height) / 2) & 0x3ff;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001797 if (accu0 >= 1024/2) {
1798 accu1 = 1024/2;
1799 accu0 -= accu1;
1800 }
1801 }
1802
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001803 dispc_ovl_set_vid_accu0(plane, 0, accu0);
1804 dispc_ovl_set_vid_accu1(plane, 0, accu1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001805}
1806
Jyri Sarha864050c2017-03-24 16:47:52 +02001807static void dispc_ovl_set_scaling_uv(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301808 u16 orig_width, u16 orig_height,
1809 u16 out_width, u16 out_height,
1810 bool ilace, bool five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001811 bool fieldmode, u32 fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301812 u8 rotation)
1813{
1814 int scale_x = out_width != orig_width;
1815 int scale_y = out_height != orig_height;
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05001816 bool chroma_upscale = plane != OMAP_DSS_WB;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301817
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001818 if (!dispc_has_feature(FEAT_HANDLE_UV_SEPARATE))
Amber Jain0d66cbb2011-05-19 19:47:54 +05301819 return;
Tomi Valkeinen5edec142017-05-04 09:13:32 +03001820
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001821 if (!format_is_yuv(fourcc)) {
Amber Jain0d66cbb2011-05-19 19:47:54 +05301822 /* reset chroma resampling for RGB formats */
Archit Taneja2a5561b2012-07-16 16:37:45 +05301823 if (plane != OMAP_DSS_WB)
1824 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301825 return;
1826 }
Tomi Valkeinen36377352012-05-15 15:54:15 +03001827
1828 dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001829 out_height, ilace, fourcc, rotation);
Tomi Valkeinen36377352012-05-15 15:54:15 +03001830
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001831 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001832 case DRM_FORMAT_NV12:
Archit Taneja20fbb502012-08-22 17:04:48 +05301833 if (chroma_upscale) {
1834 /* UV is subsampled by 2 horizontally and vertically */
1835 orig_height >>= 1;
1836 orig_width >>= 1;
1837 } else {
1838 /* UV is downsampled by 2 horizontally and vertically */
1839 orig_height <<= 1;
1840 orig_width <<= 1;
1841 }
1842
Amber Jain0d66cbb2011-05-19 19:47:54 +05301843 break;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001844 case DRM_FORMAT_YUYV:
1845 case DRM_FORMAT_UYVY:
Archit Taneja20fbb502012-08-22 17:04:48 +05301846 /* For YUV422 with 90/270 rotation, we don't upsample chroma */
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001847 if (!drm_rotation_90_or_270(rotation)) {
Archit Taneja20fbb502012-08-22 17:04:48 +05301848 if (chroma_upscale)
1849 /* UV is subsampled by 2 horizontally */
1850 orig_width >>= 1;
1851 else
1852 /* UV is downsampled by 2 horizontally */
1853 orig_width <<= 1;
1854 }
1855
Amber Jain0d66cbb2011-05-19 19:47:54 +05301856 /* must use FIR for YUV422 if rotated */
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001857 if ((rotation & DRM_MODE_ROTATE_MASK) != DRM_MODE_ROTATE_0)
Amber Jain0d66cbb2011-05-19 19:47:54 +05301858 scale_x = scale_y = true;
Archit Taneja20fbb502012-08-22 17:04:48 +05301859
Amber Jain0d66cbb2011-05-19 19:47:54 +05301860 break;
1861 default:
1862 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03001863 return;
Amber Jain0d66cbb2011-05-19 19:47:54 +05301864 }
1865
1866 if (out_width != orig_width)
1867 scale_x = true;
1868 if (out_height != orig_height)
1869 scale_y = true;
1870
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001871 dispc_ovl_set_scale_param(plane, orig_width, orig_height,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301872 out_width, out_height, five_taps,
1873 rotation, DISPC_COLOR_COMPONENT_UV);
1874
Archit Taneja2a5561b2012-07-16 16:37:45 +05301875 if (plane != OMAP_DSS_WB)
1876 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane),
1877 (scale_x || scale_y) ? 1 : 0, 8, 8);
1878
Amber Jain0d66cbb2011-05-19 19:47:54 +05301879 /* set H scaling */
1880 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5);
1881 /* set V scaling */
1882 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6);
Amber Jain0d66cbb2011-05-19 19:47:54 +05301883}
1884
Jyri Sarha864050c2017-03-24 16:47:52 +02001885static void dispc_ovl_set_scaling(enum omap_plane_id plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301886 u16 orig_width, u16 orig_height,
1887 u16 out_width, u16 out_height,
1888 bool ilace, bool five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001889 bool fieldmode, u32 fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301890 u8 rotation)
1891{
1892 BUG_ON(plane == OMAP_DSS_GFX);
1893
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001894 dispc_ovl_set_scaling_common(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301895 orig_width, orig_height,
1896 out_width, out_height,
1897 ilace, five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001898 fieldmode, fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301899 rotation);
1900
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03001901 dispc_ovl_set_scaling_uv(plane,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301902 orig_width, orig_height,
1903 out_width, out_height,
1904 ilace, five_taps,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001905 fieldmode, fourcc,
Amber Jain0d66cbb2011-05-19 19:47:54 +05301906 rotation);
1907}
1908
Jyri Sarha273ffea2017-03-24 16:47:53 +02001909static void dispc_ovl_set_rotation_attrs(enum omap_plane_id plane, u8 rotation,
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03001910 enum omap_dss_rotation_type rotation_type, u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001911{
Archit Taneja87a74842011-03-02 11:19:50 +05301912 bool row_repeat = false;
1913 int vidrot = 0;
1914
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001915 /* Note: DSS HW rotates clockwise, DRM_MODE_ROTATE_* counter-clockwise */
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001916 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY) {
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001917
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03001918 if (rotation & DRM_MODE_REFLECT_X) {
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001919 switch (rotation & DRM_MODE_ROTATE_MASK) {
1920 case DRM_MODE_ROTATE_0:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001921 vidrot = 2;
1922 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001923 case DRM_MODE_ROTATE_90:
Tomi Valkeinen2add8d132017-05-16 15:25:45 +03001924 vidrot = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001925 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001926 case DRM_MODE_ROTATE_180:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001927 vidrot = 0;
1928 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001929 case DRM_MODE_ROTATE_270:
Tomi Valkeinen2add8d132017-05-16 15:25:45 +03001930 vidrot = 3;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001931 break;
1932 }
1933 } else {
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001934 switch (rotation & DRM_MODE_ROTATE_MASK) {
1935 case DRM_MODE_ROTATE_0:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001936 vidrot = 0;
1937 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001938 case DRM_MODE_ROTATE_90:
1939 vidrot = 3;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001940 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001941 case DRM_MODE_ROTATE_180:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001942 vidrot = 2;
1943 break;
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001944 case DRM_MODE_ROTATE_270:
1945 vidrot = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001946 break;
1947 }
1948 }
1949
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001950 if (drm_rotation_90_or_270(rotation))
Archit Taneja87a74842011-03-02 11:19:50 +05301951 row_repeat = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001952 else
Archit Taneja87a74842011-03-02 11:19:50 +05301953 row_repeat = false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001954 }
Archit Taneja87a74842011-03-02 11:19:50 +05301955
Tomi Valkeinen3397cc62015-04-09 13:51:30 +03001956 /*
1957 * OMAP4/5 Errata i631:
1958 * NV12 in 1D mode must use ROTATION=1. Otherwise DSS will fetch extra
1959 * rows beyond the framebuffer, which may cause OCP error.
1960 */
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001961 if (fourcc == DRM_FORMAT_NV12 && rotation_type != OMAP_DSS_ROT_TILER)
Tomi Valkeinen3397cc62015-04-09 13:51:30 +03001962 vidrot = 1;
1963
Archit Taneja9b372c22011-05-06 11:45:49 +05301964 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), vidrot, 13, 12);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03001965 if (dispc_has_feature(FEAT_ROWREPEATENABLE))
Archit Taneja9b372c22011-05-06 11:45:49 +05301966 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane),
1967 row_repeat ? 1 : 0, 18, 18);
Archit Tanejac35eeb22013-03-26 19:15:24 +05301968
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03001969 if (dispc_ovl_color_mode_supported(plane, DRM_FORMAT_NV12)) {
Tomi Valkeinen6d862782016-08-29 11:15:49 +03001970 bool doublestride =
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001971 fourcc == DRM_FORMAT_NV12 &&
Tomi Valkeinen6d862782016-08-29 11:15:49 +03001972 rotation_type == OMAP_DSS_ROT_TILER &&
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03001973 !drm_rotation_90_or_270(rotation);
Tomi Valkeinen6d862782016-08-29 11:15:49 +03001974
Archit Tanejac35eeb22013-03-26 19:15:24 +05301975 /* DOUBLESTRIDE */
1976 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), doublestride, 22, 22);
1977 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001978}
1979
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001980static int color_mode_to_bpp(u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001981{
Tomi Valkeinen41aff422017-05-04 11:31:56 +03001982 switch (fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001983 case DRM_FORMAT_NV12:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001984 return 8;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001985 case DRM_FORMAT_RGBX4444:
1986 case DRM_FORMAT_RGB565:
1987 case DRM_FORMAT_ARGB4444:
1988 case DRM_FORMAT_YUYV:
1989 case DRM_FORMAT_UYVY:
1990 case DRM_FORMAT_RGBA4444:
1991 case DRM_FORMAT_XRGB4444:
1992 case DRM_FORMAT_ARGB1555:
1993 case DRM_FORMAT_XRGB1555:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001994 return 16;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001995 case DRM_FORMAT_RGB888:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02001996 return 24;
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03001997 case DRM_FORMAT_XRGB8888:
1998 case DRM_FORMAT_ARGB8888:
1999 case DRM_FORMAT_RGBA8888:
2000 case DRM_FORMAT_RGBX8888:
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002001 return 32;
2002 default:
2003 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002004 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002005 }
2006}
2007
2008static s32 pixinc(int pixels, u8 ps)
2009{
2010 if (pixels == 1)
2011 return 1;
2012 else if (pixels > 1)
2013 return 1 + (pixels - 1) * ps;
2014 else if (pixels < 0)
2015 return 1 - (-pixels + 1) * ps;
2016 else
2017 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002018 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002019}
2020
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03002021static void calc_offset(u16 screen_width, u16 width,
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02002022 u32 fourcc, bool fieldmode, unsigned int field_offset,
2023 unsigned int *offset0, unsigned int *offset1,
Tomi Valkeinenc4df6e42017-05-15 11:09:25 +03002024 s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim,
2025 enum omap_dss_rotation_type rotation_type, u8 rotation)
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302026{
2027 u8 ps;
2028
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002029 ps = color_mode_to_bpp(fourcc) / 8;
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302030
2031 DSSDBG("scrw %d, width %d\n", screen_width, width);
2032
Tomi Valkeinenc4df6e42017-05-15 11:09:25 +03002033 if (rotation_type == OMAP_DSS_ROT_TILER &&
2034 (fourcc == DRM_FORMAT_UYVY || fourcc == DRM_FORMAT_YUYV) &&
2035 drm_rotation_90_or_270(rotation)) {
2036 /*
2037 * HACK: ROW_INC needs to be calculated with TILER units.
2038 * We get such 'screen_width' that multiplying it with the
2039 * YUV422 pixel size gives the correct TILER container width.
2040 * However, 'width' is in pixels and multiplying it with YUV422
2041 * pixel size gives incorrect result. We thus multiply it here
2042 * with 2 to match the 32 bit TILER unit size.
2043 */
2044 width *= 2;
2045 }
2046
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302047 /*
2048 * field 0 = even field = bottom field
2049 * field 1 = odd field = top field
2050 */
Tomi Valkeinen185e23e2017-05-03 15:01:10 +03002051 *offset0 = field_offset * screen_width * ps;
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302052 *offset1 = 0;
Tomi Valkeinen185e23e2017-05-03 15:01:10 +03002053
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302054 *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) +
2055 (fieldmode ? screen_width : 0), ps);
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002056 if (fourcc == DRM_FORMAT_YUYV || fourcc == DRM_FORMAT_UYVY)
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302057 *pix_inc = pixinc(x_predecim, 2 * ps);
2058 else
2059 *pix_inc = pixinc(x_predecim, ps);
2060}
2061
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302062/*
2063 * This function is used to avoid synclosts in OMAP3, because of some
2064 * undocumented horizontal position and timing related limitations.
2065 */
Tomi Valkeinen465ec132012-10-19 15:40:24 +03002066static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002067 const struct videomode *vm, u16 pos_x,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002068 u16 width, u16 height, u16 out_width, u16 out_height,
2069 bool five_taps)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302070{
Tomi Valkeinen230edc02012-11-05 14:40:19 +02002071 const int ds = DIV_ROUND_UP(height, out_height);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302072 unsigned long nonactive;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302073 static const u8 limits[3] = { 8, 10, 20 };
2074 u64 val, blank;
2075 int i;
2076
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002077 nonactive = vm->hactive + vm->hfront_porch + vm->hsync_len +
2078 vm->hback_porch - out_width;
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302079
2080 i = 0;
2081 if (out_height < height)
2082 i++;
2083 if (out_width < width)
2084 i++;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002085 blank = div_u64((u64)(vm->hback_porch + vm->hsync_len + vm->hfront_porch) *
Peter Ujfalusi0a30e152016-09-22 14:06:49 +03002086 lclk, pclk);
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302087 DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]);
2088 if (blank <= limits[i])
2089 return -EINVAL;
2090
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002091 /* FIXME add checks for 3-tap filter once the limitations are known */
2092 if (!five_taps)
2093 return 0;
2094
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302095 /*
2096 * Pixel data should be prepared before visible display point starts.
2097 * So, atleast DS-2 lines must have already been fetched by DISPC
2098 * during nonactive - pos_x period.
2099 */
2100 val = div_u64((u64)(nonactive - pos_x) * lclk, pclk);
2101 DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n",
Tomi Valkeinen230edc02012-11-05 14:40:19 +02002102 val, max(0, ds - 2) * width);
2103 if (val < max(0, ds - 2) * width)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302104 return -EINVAL;
2105
2106 /*
2107 * All lines need to be refilled during the nonactive period of which
2108 * only one line can be loaded during the active period. So, atleast
2109 * DS - 1 lines should be loaded during nonactive period.
2110 */
2111 val = div_u64((u64)nonactive * lclk, pclk);
2112 DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n",
Tomi Valkeinen230edc02012-11-05 14:40:19 +02002113 val, max(0, ds - 1) * width);
2114 if (val < max(0, ds - 1) * width)
Chandrabhanu Mahapatra7faa9232012-04-02 20:43:17 +05302115 return -EINVAL;
2116
2117 return 0;
2118}
2119
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002120static unsigned long calc_core_clk_five_taps(unsigned long pclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002121 const struct videomode *vm, u16 width,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302122 u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002123 u32 fourcc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002124{
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302125 u32 core_clk = 0;
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302126 u64 tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002127
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302128 if (height <= out_height && width <= out_width)
2129 return (unsigned long) pclk;
2130
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002131 if (height > out_height) {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002132 unsigned int ppl = vm->hactive;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002133
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002134 tmp = (u64)pclk * height * out_width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002135 do_div(tmp, 2 * out_height * ppl);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302136 core_clk = tmp;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002137
Ville Syrjälä2d9c5592010-01-08 11:56:41 +02002138 if (height > 2 * out_height) {
2139 if (ppl == out_width)
2140 return 0;
2141
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002142 tmp = (u64)pclk * (height - 2 * out_height) * out_width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002143 do_div(tmp, 2 * out_height * (ppl - out_width));
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302144 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002145 }
2146 }
2147
2148 if (width > out_width) {
Tomi Valkeinenc5829352015-04-10 12:48:36 +03002149 tmp = (u64)pclk * width;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002150 do_div(tmp, out_width);
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302151 core_clk = max_t(u32, core_clk, tmp);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002152
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002153 if (fourcc == DRM_FORMAT_XRGB8888)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302154 core_clk <<= 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002155 }
2156
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302157 return core_clk;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002158}
2159
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002160static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302161 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302162{
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302163 if (height > out_height && width > out_width)
2164 return pclk * 4;
2165 else
2166 return pclk * 2;
2167}
2168
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002169static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302170 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002171{
2172 unsigned int hf, vf;
2173
2174 /*
2175 * FIXME how to determine the 'A' factor
2176 * for the no downscaling case ?
2177 */
2178
2179 if (width > 3 * out_width)
2180 hf = 4;
2181 else if (width > 2 * out_width)
2182 hf = 3;
2183 else if (width > out_width)
2184 hf = 2;
2185 else
2186 hf = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002187 if (height > out_height)
2188 vf = 2;
2189 else
2190 vf = 1;
2191
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302192 return pclk * vf * hf;
2193}
2194
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002195static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302196 u16 height, u16 out_width, u16 out_height, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302197{
Archit Taneja8ba85302012-09-26 17:00:37 +05302198 /*
2199 * If the overlay/writeback is in mem to mem mode, there are no
2200 * downscaling limitations with respect to pixel clock, return 1 as
2201 * required core clock to represent that we have sufficient enough
2202 * core clock to do maximum downscaling
2203 */
2204 if (mem_to_mem)
2205 return 1;
2206
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302207 if (width > out_width)
2208 return DIV_ROUND_UP(pclk, out_width) * width;
2209 else
2210 return pclk;
2211}
2212
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002213static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002214 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302215 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002216 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302217 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302218 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302219{
2220 int error;
2221 u16 in_width, in_height;
2222 int min_factor = min(*decim_x, *decim_y);
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03002223 const int maxsinglelinewidth = dispc.feat->max_line_width;
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302224
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302225 *five_taps = false;
2226
2227 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002228 in_height = height / *decim_y;
2229 in_width = width / *decim_x;
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002230 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302231 in_height, out_width, out_height, mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302232 error = (in_width > maxsinglelinewidth || !*core_clk ||
2233 *core_clk > dispc_core_clk_rate());
2234 if (error) {
2235 if (*decim_x == *decim_y) {
2236 *decim_x = min_factor;
2237 ++*decim_y;
2238 } else {
2239 swap(*decim_x, *decim_y);
2240 if (*decim_x < *decim_y)
2241 ++*decim_x;
2242 }
2243 }
2244 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2245
Tomi Valkeinen3ce17b42015-04-10 12:48:37 +03002246 if (error) {
2247 DSSERR("failed to find scaling settings\n");
2248 return -EINVAL;
2249 }
2250
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302251 if (in_width > maxsinglelinewidth) {
2252 DSSERR("Cannot scale max input width exceeded");
2253 return -EINVAL;
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302254 }
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302255 return 0;
2256}
2257
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002258static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002259 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302260 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002261 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302262 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302263 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302264{
2265 int error;
2266 u16 in_width, in_height;
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03002267 const int maxsinglelinewidth = dispc.feat->max_line_width;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302268
2269 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002270 in_height = height / *decim_y;
2271 in_width = width / *decim_x;
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002272 *five_taps = in_height > out_height;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302273
2274 if (in_width > maxsinglelinewidth)
2275 if (in_height > out_height &&
2276 in_height < out_height * 2)
2277 *five_taps = false;
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002278again:
2279 if (*five_taps)
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002280 *core_clk = calc_core_clk_five_taps(pclk, vm,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002281 in_width, in_height, out_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002282 out_height, fourcc);
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002283 else
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002284 *core_clk = dispc.feat->calc_core_clk(pclk, in_width,
Archit Taneja8ba85302012-09-26 17:00:37 +05302285 in_height, out_width, out_height,
2286 mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302287
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002288 error = check_horiz_timing_omap3(pclk, lclk, vm,
Ivaylo Dimitrove49986342014-01-13 18:33:02 +02002289 pos_x, in_width, in_height, out_width,
2290 out_height, *five_taps);
2291 if (error && *five_taps) {
2292 *five_taps = false;
2293 goto again;
2294 }
2295
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302296 error = (error || in_width > maxsinglelinewidth * 2 ||
2297 (in_width > maxsinglelinewidth && *five_taps) ||
2298 !*core_clk || *core_clk > dispc_core_clk_rate());
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002299
2300 if (!error) {
2301 /* verify that we're inside the limits of scaler */
2302 if (in_width / 4 > out_width)
2303 error = 1;
2304
2305 if (*five_taps) {
2306 if (in_height / 4 > out_height)
2307 error = 1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302308 } else {
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002309 if (in_height / 2 > out_height)
2310 error = 1;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302311 }
2312 }
Tomi Valkeinenab6b2582015-03-17 15:31:10 +02002313
Tomi Valkeinen7059e3d2015-04-10 12:48:38 +03002314 if (error)
2315 ++*decim_y;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302316 } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error);
2317
Tomi Valkeinen3ce17b42015-04-10 12:48:37 +03002318 if (error) {
2319 DSSERR("failed to find scaling settings\n");
2320 return -EINVAL;
2321 }
2322
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002323 if (check_horiz_timing_omap3(pclk, lclk, vm, pos_x, in_width,
Tomi Valkeinenf5a73482015-03-17 15:31:09 +02002324 in_height, out_width, out_height, *five_taps)) {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302325 DSSERR("horizontal timing too tight\n");
2326 return -EINVAL;
2327 }
2328
2329 if (in_width > (maxsinglelinewidth * 2)) {
2330 DSSERR("Cannot setup scaling");
2331 DSSERR("width exceeds maximum width possible");
2332 return -EINVAL;
2333 }
2334
2335 if (in_width > maxsinglelinewidth && *five_taps) {
2336 DSSERR("cannot setup scaling with five taps");
2337 return -EINVAL;
2338 }
2339 return 0;
2340}
2341
Tomi Valkeinen0c6921d2012-10-19 15:43:29 +03002342static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002343 const struct videomode *vm,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302344 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002345 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302346 int *x_predecim, int *y_predecim, int *decim_x, int *decim_y,
Archit Taneja8ba85302012-09-26 17:00:37 +05302347 u16 pos_x, unsigned long *core_clk, bool mem_to_mem)
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302348{
2349 u16 in_width, in_width_max;
2350 int decim_x_min = *decim_x;
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002351 u16 in_height = height / *decim_y;
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03002352 const int maxsinglelinewidth = dispc.feat->max_line_width;
2353 const int maxdownscale = dispc.feat->max_downscale;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302354
Archit Taneja5d501082012-11-07 11:45:02 +05302355 if (mem_to_mem) {
2356 in_width_max = out_width * maxdownscale;
2357 } else {
Archit Taneja8ba85302012-09-26 17:00:37 +05302358 in_width_max = dispc_core_clk_rate() /
2359 DIV_ROUND_UP(pclk, out_width);
Archit Taneja5d501082012-11-07 11:45:02 +05302360 }
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302361
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302362 *decim_x = DIV_ROUND_UP(width, in_width_max);
2363
2364 *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min;
2365 if (*decim_x > *x_predecim)
2366 return -EINVAL;
2367
2368 do {
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002369 in_width = width / *decim_x;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302370 } while (*decim_x <= *x_predecim &&
2371 in_width > maxsinglelinewidth && ++*decim_x);
2372
2373 if (in_width > maxsinglelinewidth) {
2374 DSSERR("Cannot scale width exceeds max line width");
2375 return -EINVAL;
2376 }
2377
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002378 if (*decim_x > 4 && fourcc != DRM_FORMAT_NV12) {
Jyri Sarha1b30ab02017-02-08 16:08:06 +02002379 /*
2380 * Let's disable all scaling that requires horizontal
2381 * decimation with higher factor than 4, until we have
2382 * better estimates of what we can and can not
2383 * do. However, NV12 color format appears to work Ok
2384 * with all decimation factors.
2385 *
2386 * When decimating horizontally by more that 4 the dss
2387 * is not able to fetch the data in burst mode. When
2388 * this happens it is hard to tell if there enough
2389 * bandwidth. Despite what theory says this appears to
2390 * be true also for 16-bit color formats.
2391 */
2392 DSSERR("Not enough bandwidth, too much downscaling (x-decimation factor %d > 4)", *decim_x);
2393
2394 return -EINVAL;
2395 }
2396
Tomi Valkeinen8702ee52012-10-19 15:36:11 +03002397 *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height,
Archit Taneja8ba85302012-09-26 17:00:37 +05302398 out_width, out_height, mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302399 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002400}
2401
Tomi Valkeinene4c5ae72015-04-10 12:48:39 +03002402#define DIV_FRAC(dividend, divisor) \
2403 ((dividend) * 100 / (divisor) - ((dividend) / (divisor) * 100))
2404
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002405static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302406 enum omap_overlay_caps caps,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002407 const struct videomode *vm,
Archit Taneja81ab95b2012-05-08 15:53:20 +05302408 u16 width, u16 height, u16 out_width, u16 out_height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002409 u32 fourcc, bool *five_taps,
Chandrabhanu Mahapatrad557a9c2012-09-24 12:08:27 +05302410 int *x_predecim, int *y_predecim, u16 pos_x,
Archit Taneja8ba85302012-09-26 17:00:37 +05302411 enum omap_dss_rotation_type rotation_type, bool mem_to_mem)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302412{
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03002413 const int maxdownscale = dispc.feat->max_downscale;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302414 const int max_decim_limit = 16;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302415 unsigned long core_clk = 0;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302416 int decim_x, decim_y, ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302417
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002418 if (width == out_width && height == out_height)
2419 return 0;
2420
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002421 if (!mem_to_mem && (pclk == 0 || vm->pixelclock == 0)) {
Tomi Valkeinen4e1d3ca2014-10-03 15:14:09 +00002422 DSSERR("cannot calculate scaling settings: pclk is zero\n");
2423 return -EINVAL;
2424 }
2425
Archit Taneja5b54ed32012-09-26 16:55:27 +05302426 if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0)
Tomi Valkeinenf95cb5e2011-11-01 10:50:45 +02002427 return -EINVAL;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302428
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002429 if (mem_to_mem) {
Archit Taneja1c031442012-11-07 11:45:03 +05302430 *x_predecim = *y_predecim = 1;
2431 } else {
2432 *x_predecim = max_decim_limit;
2433 *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER &&
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03002434 dispc_has_feature(FEAT_BURST_2D)) ?
Archit Taneja1c031442012-11-07 11:45:03 +05302435 2 : max_decim_limit;
2436 }
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302437
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302438 decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale);
2439 decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale);
2440
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302441 if (decim_x > *x_predecim || out_width > width * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302442 return -EINVAL;
2443
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302444 if (decim_y > *y_predecim || out_height > height * 8)
Archit Taneja79ad75f2011-09-08 13:15:11 +05302445 return -EINVAL;
2446
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002447 ret = dispc.feat->calc_scaling(pclk, lclk, vm, width, height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002448 out_width, out_height, fourcc, five_taps,
Archit Taneja8ba85302012-09-26 17:00:37 +05302449 x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk,
2450 mem_to_mem);
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302451 if (ret)
2452 return ret;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302453
Tomi Valkeinene4c5ae72015-04-10 12:48:39 +03002454 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",
2455 width, height,
2456 out_width, out_height,
2457 out_width / width, DIV_FRAC(out_width, width),
2458 out_height / height, DIV_FRAC(out_height, height),
2459
2460 decim_x, decim_y,
2461 width / decim_x, height / decim_y,
2462 out_width / (width / decim_x), DIV_FRAC(out_width, width / decim_x),
2463 out_height / (height / decim_y), DIV_FRAC(out_height, height / decim_y),
2464
2465 *five_taps ? 5 : 3,
2466 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302467
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302468 if (!core_clk || core_clk > dispc_core_clk_rate()) {
Archit Taneja79ad75f2011-09-08 13:15:11 +05302469 DSSERR("failed to set up scaling, "
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05302470 "required core clk rate = %lu Hz, "
2471 "current core clk rate = %lu Hz\n",
2472 core_clk, dispc_core_clk_rate());
Archit Taneja79ad75f2011-09-08 13:15:11 +05302473 return -EINVAL;
2474 }
2475
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302476 *x_predecim = decim_x;
2477 *y_predecim = decim_y;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302478 return 0;
2479}
2480
Jyri Sarha864050c2017-03-24 16:47:52 +02002481static int dispc_ovl_setup_common(enum omap_plane_id plane,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302482 enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr,
2483 u16 screen_width, int pos_x, int pos_y, u16 width, u16 height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002484 u16 out_width, u16 out_height, u32 fourcc,
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002485 u8 rotation, u8 zorder, u8 pre_mult_alpha,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302486 u8 global_alpha, enum omap_dss_rotation_type rotation_type,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002487 bool replication, const struct videomode *vm,
Archit Taneja8ba85302012-09-26 17:00:37 +05302488 bool mem_to_mem)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002489{
Chandrabhanu Mahapatra7282f1b2011-12-19 14:03:56 +05302490 bool five_taps = true;
Peter Senna Tschudin62a83182013-09-22 20:44:11 +02002491 bool fieldmode = false;
Archit Taneja79ad75f2011-09-08 13:15:11 +05302492 int r, cconv = 0;
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02002493 unsigned int offset0, offset1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002494 s32 row_inc;
2495 s32 pix_inc;
Archit Taneja6be0d732012-11-07 11:45:04 +05302496 u16 frame_width, frame_height;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002497 unsigned int field_offset = 0;
Archit Taneja84a880f2012-09-26 16:57:37 +05302498 u16 in_height = height;
2499 u16 in_width = width;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302500 int x_predecim = 1, y_predecim = 1;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002501 bool ilace = !!(vm->flags & DISPLAY_FLAGS_INTERLACED);
Tomi Valkeinen74e16452012-10-19 15:46:30 +03002502 unsigned long pclk = dispc_plane_pclk_rate(plane);
2503 unsigned long lclk = dispc_plane_lclk_rate(plane);
Tomi Valkeinen2cc5d1a2011-11-03 17:03:44 +02002504
Tomi Valkeinene5666582014-11-28 14:34:15 +02002505 if (paddr == 0 && rotation_type != OMAP_DSS_ROT_TILER)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002506 return -EINVAL;
2507
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002508 if (format_is_yuv(fourcc) && (in_width & 1)) {
Tomi Valkeinen5edec142017-05-04 09:13:32 +03002509 DSSERR("input width %d is not even for YUV format\n", in_width);
2510 return -EINVAL;
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002511 }
2512
Archit Taneja84a880f2012-09-26 16:57:37 +05302513 out_width = out_width == 0 ? width : out_width;
2514 out_height = out_height == 0 ? height : out_height;
Tomi Valkeinencf073662011-11-03 16:08:27 +02002515
Archit Taneja84a880f2012-09-26 16:57:37 +05302516 if (ilace && height == out_height)
Peter Senna Tschudin62a83182013-09-22 20:44:11 +02002517 fieldmode = true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002518
2519 if (ilace) {
2520 if (fieldmode)
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302521 in_height /= 2;
Archit Taneja8eeb7012012-08-22 12:33:49 +05302522 pos_y /= 2;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302523 out_height /= 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002524
2525 DSSDBG("adjusting for ilace: height %d, pos_y %d, "
Archit Taneja84a880f2012-09-26 16:57:37 +05302526 "out_height %d\n", in_height, pos_y,
2527 out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002528 }
2529
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03002530 if (!dispc_ovl_color_mode_supported(plane, fourcc))
Archit Taneja8dad2ab2010-11-25 17:58:10 +05302531 return -EINVAL;
2532
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002533 r = dispc_ovl_calc_scaling(pclk, lclk, caps, vm, in_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002534 in_height, out_width, out_height, fourcc,
Archit Taneja84a880f2012-09-26 16:57:37 +05302535 &five_taps, &x_predecim, &y_predecim, pos_x,
Archit Taneja8ba85302012-09-26 17:00:37 +05302536 rotation_type, mem_to_mem);
Archit Taneja79ad75f2011-09-08 13:15:11 +05302537 if (r)
2538 return r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002539
Tomi Valkeineneec77da2014-01-27 11:29:53 +02002540 in_width = in_width / x_predecim;
2541 in_height = in_height / y_predecim;
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302542
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002543 if (x_predecim > 1 || y_predecim > 1)
2544 DSSDBG("predecimation %d x %x, new input size %d x %d\n",
2545 x_predecim, y_predecim, in_width, in_height);
2546
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002547 if (format_is_yuv(fourcc) && (in_width & 1)) {
Tomi Valkeinen5edec142017-05-04 09:13:32 +03002548 DSSDBG("predecimated input width is not even for YUV format\n");
2549 DSSDBG("adjusting input width %d -> %d\n",
2550 in_width, in_width & ~1);
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002551
Tomi Valkeinen5edec142017-05-04 09:13:32 +03002552 in_width &= ~1;
Tomi Valkeinenc4661b32015-02-27 13:07:58 +02002553 }
2554
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002555 if (format_is_yuv(fourcc))
Archit Taneja79ad75f2011-09-08 13:15:11 +05302556 cconv = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002557
2558 if (ilace && !fieldmode) {
2559 /*
2560 * when downscaling the bottom field may have to start several
2561 * source lines below the top field. Unfortunately ACCUI
2562 * registers will only hold the fractional part of the offset
2563 * so the integer part must be added to the base address of the
2564 * bottom field.
2565 */
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302566 if (!in_height || in_height == out_height)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002567 field_offset = 0;
2568 else
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302569 field_offset = in_height / out_height / 2;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002570 }
2571
2572 /* Fields are independent but interleaved in memory. */
2573 if (fieldmode)
2574 field_offset = 1;
2575
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03002576 offset0 = 0;
2577 offset1 = 0;
2578 row_inc = 0;
2579 pix_inc = 0;
2580
Archit Taneja6be0d732012-11-07 11:45:04 +05302581 if (plane == OMAP_DSS_WB) {
2582 frame_width = out_width;
2583 frame_height = out_height;
2584 } else {
2585 frame_width = in_width;
2586 frame_height = height;
2587 }
2588
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03002589 calc_offset(screen_width, frame_width,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002590 fourcc, fieldmode, field_offset,
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03002591 &offset0, &offset1, &row_inc, &pix_inc,
Tomi Valkeinenc4df6e42017-05-15 11:09:25 +03002592 x_predecim, y_predecim,
2593 rotation_type, rotation);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002594
2595 DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n",
2596 offset0, offset1, row_inc, pix_inc);
2597
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002598 dispc_ovl_set_color_mode(plane, fourcc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002599
Archit Taneja84a880f2012-09-26 16:57:37 +05302600 dispc_ovl_configure_burst_type(plane, rotation_type);
Chandrabhanu Mahapatra65e006f2012-05-11 19:19:55 +05302601
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02002602 if (dispc.feat->reverse_ilace_field_order)
2603 swap(offset0, offset1);
2604
Archit Taneja84a880f2012-09-26 16:57:37 +05302605 dispc_ovl_set_ba0(plane, paddr + offset0);
2606 dispc_ovl_set_ba1(plane, paddr + offset1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002607
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002608 if (fourcc == DRM_FORMAT_NV12) {
Archit Taneja84a880f2012-09-26 16:57:37 +05302609 dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0);
2610 dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1);
Amber Jain0d66cbb2011-05-19 19:47:54 +05302611 }
2612
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03002613 if (dispc.feat->last_pixel_inc_missing)
2614 row_inc += pix_inc - 1;
2615
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002616 dispc_ovl_set_row_inc(plane, row_inc);
2617 dispc_ovl_set_pix_inc(plane, pix_inc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002618
Archit Taneja84a880f2012-09-26 16:57:37 +05302619 DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width,
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302620 in_height, out_width, out_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002621
Archit Taneja84a880f2012-09-26 16:57:37 +05302622 dispc_ovl_set_pos(plane, caps, pos_x, pos_y);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002623
Archit Taneja78b687f2012-09-21 14:51:49 +05302624 dispc_ovl_set_input_size(plane, in_width, in_height);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002625
Archit Taneja5b54ed32012-09-26 16:55:27 +05302626 if (caps & OMAP_DSS_OVL_CAP_SCALE) {
Chandrabhanu Mahapatraaed74b552012-04-02 20:43:16 +05302627 dispc_ovl_set_scaling(plane, in_width, in_height, out_width,
2628 out_height, ilace, five_taps, fieldmode,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002629 fourcc, rotation);
Archit Taneja78b687f2012-09-21 14:51:49 +05302630 dispc_ovl_set_output_size(plane, out_width, out_height);
Tomi Valkeinenf0e5caa2011-08-16 13:25:00 +03002631 dispc_ovl_set_vid_color_conv(plane, cconv);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002632 }
2633
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002634 dispc_ovl_set_rotation_attrs(plane, rotation, rotation_type, fourcc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002635
Archit Taneja84a880f2012-09-26 16:57:37 +05302636 dispc_ovl_set_zorder(plane, caps, zorder);
2637 dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha);
2638 dispc_ovl_setup_global_alpha(plane, caps, global_alpha);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002639
Archit Tanejad79db852012-09-22 12:30:17 +05302640 dispc_ovl_enable_replication(plane, caps, replication);
Archit Tanejac3d925292011-09-14 11:52:54 +05302641
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002642 return 0;
2643}
2644
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002645static int dispc_ovl_setup(struct dispc_device *dispc,
2646 enum omap_plane_id plane,
2647 const struct omap_overlay_info *oi,
2648 const struct videomode *vm, bool mem_to_mem,
2649 enum omap_channel channel)
Archit Taneja84a880f2012-09-26 16:57:37 +05302650{
2651 int r;
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002652 enum omap_overlay_caps caps = dispc->feat->overlay_caps[plane];
Tomi Valkeinenbe2d68c2016-08-29 13:15:02 +03002653 const bool replication = true;
Archit Taneja84a880f2012-09-26 16:57:37 +05302654
Arnd Bergmann24f13a62014-04-24 13:28:18 +01002655 DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002656 " %dx%d, cmode %x, rot %d, chan %d repl %d\n",
Arnd Bergmann24f13a62014-04-24 13:28:18 +01002657 plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
Archit Taneja84a880f2012-09-26 16:57:37 +05302658 oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002659 oi->fourcc, oi->rotation, channel, replication);
Archit Taneja84a880f2012-09-26 16:57:37 +05302660
Tomi Valkeinen49a30572017-02-17 12:30:07 +02002661 dispc_ovl_set_channel_out(plane, channel);
2662
Tomi Valkeinen16bf20c2012-10-15 15:33:22 +03002663 r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr,
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05302664 oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002665 oi->out_width, oi->out_height, oi->fourcc, oi->rotation,
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002666 oi->zorder, oi->pre_mult_alpha, oi->global_alpha,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002667 oi->rotation_type, replication, vm, mem_to_mem);
Archit Taneja84a880f2012-09-26 16:57:37 +05302668
2669 return r;
2670}
2671
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02002672int dispc_wb_setup(struct dispc_device *dispc,
2673 const struct omap_dss_writeback_info *wi,
2674 bool mem_to_mem, const struct videomode *vm)
Archit Taneja749feff2012-08-31 12:32:52 +05302675{
2676 int r;
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302677 u32 l;
Jyri Sarha864050c2017-03-24 16:47:52 +02002678 enum omap_plane_id plane = OMAP_DSS_WB;
Archit Taneja749feff2012-08-31 12:32:52 +05302679 const int pos_x = 0, pos_y = 0;
2680 const u8 zorder = 0, global_alpha = 0;
Tomi Valkeinenbe2d68c2016-08-29 13:15:02 +03002681 const bool replication = true;
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302682 bool truncation;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002683 int in_width = vm->hactive;
2684 int in_height = vm->vactive;
Archit Taneja749feff2012-08-31 12:32:52 +05302685 enum omap_overlay_caps caps =
2686 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA;
2687
2688 DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, "
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002689 "rot %d\n", wi->paddr, wi->p_uv_addr, in_width,
2690 in_height, wi->width, wi->height, wi->fourcc, wi->rotation);
Archit Taneja749feff2012-08-31 12:32:52 +05302691
2692 r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr,
2693 wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width,
Tomi Valkeinen4eebb802017-05-16 12:05:24 +03002694 wi->height, wi->fourcc, wi->rotation, zorder,
Archit Taneja749feff2012-08-31 12:32:52 +05302695 wi->pre_mult_alpha, global_alpha, wi->rotation_type,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002696 replication, vm, mem_to_mem);
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302697
Tomi Valkeinen41aff422017-05-04 11:31:56 +03002698 switch (wi->fourcc) {
Tomi Valkeinen3e1d65c2017-05-04 10:40:46 +03002699 case DRM_FORMAT_RGB565:
2700 case DRM_FORMAT_RGB888:
2701 case DRM_FORMAT_ARGB4444:
2702 case DRM_FORMAT_RGBA4444:
2703 case DRM_FORMAT_RGBX4444:
2704 case DRM_FORMAT_ARGB1555:
2705 case DRM_FORMAT_XRGB1555:
2706 case DRM_FORMAT_XRGB4444:
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302707 truncation = true;
2708 break;
2709 default:
2710 truncation = false;
2711 break;
2712 }
2713
2714 /* setup extra DISPC_WB_ATTRIBUTES */
2715 l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane));
2716 l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */
2717 l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */
Tomi Valkeinen4c055ce2015-11-04 17:10:53 +02002718 if (mem_to_mem)
2719 l = FLD_MOD(l, 1, 26, 24); /* CAPTUREMODE */
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002720 else
2721 l = FLD_MOD(l, 0, 26, 24); /* CAPTUREMODE */
Archit Taneja9e4a0fc2012-08-24 16:59:26 +05302722 dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l);
Archit Taneja749feff2012-08-31 12:32:52 +05302723
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002724 if (mem_to_mem) {
2725 /* WBDELAYCOUNT */
2726 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 7, 0);
2727 } else {
2728 int wbdelay;
2729
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002730 wbdelay = min(vm->vfront_porch +
2731 vm->vsync_len + vm->vback_porch, (u32)255);
Tomi Valkeinen98cd5792015-11-04 17:10:54 +02002732
2733 /* WBDELAYCOUNT */
2734 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), wbdelay, 7, 0);
2735 }
2736
Archit Taneja749feff2012-08-31 12:32:52 +05302737 return r;
2738}
2739
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002740static int dispc_ovl_enable(struct dispc_device *dispc,
2741 enum omap_plane_id plane, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002742{
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002743 DSSDBG("dispc_enable_plane %d, %d\n", plane, enable);
2744
Archit Taneja9b372c22011-05-06 11:45:49 +05302745 REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0);
Tomi Valkeinene6d80f92011-05-19 14:12:26 +03002746
2747 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002748}
2749
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002750static enum omap_dss_output_id
2751dispc_mgr_get_supported_outputs(struct dispc_device *dispc,
2752 enum omap_channel channel)
Tomi Valkeinen7b9cb5e2015-11-04 15:11:25 +02002753{
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002754 return dss_get_supported_outputs(dispc->dss, channel);
Tomi Valkeinen7b9cb5e2015-11-04 15:11:25 +02002755}
Tomi Valkeinen7b9cb5e2015-11-04 15:11:25 +02002756
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002757static void dispc_lcd_enable_signal_polarity(bool act_high)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002758{
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03002759 if (!dispc_has_feature(FEAT_LCDENABLEPOL))
Archit Taneja6ced40b2010-12-02 11:27:13 +00002760 return;
2761
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002762 REG_FLD_MOD(DISPC_CONTROL, act_high ? 1 : 0, 29, 29);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002763}
2764
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02002765void dispc_lcd_enable_signal(struct dispc_device *dispc, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002766{
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03002767 if (!dispc_has_feature(FEAT_LCDENABLESIGNAL))
Archit Taneja6ced40b2010-12-02 11:27:13 +00002768 return;
2769
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002770 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 28, 28);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002771}
2772
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02002773void dispc_pck_free_enable(struct dispc_device *dispc, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002774{
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03002775 if (!dispc_has_feature(FEAT_PCKFREEENABLE))
Archit Taneja6ced40b2010-12-02 11:27:13 +00002776 return;
2777
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002778 REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002779}
2780
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002781static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002782{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302783 mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002784}
2785
2786
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002787static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002788{
Archit Tanejad21f43b2012-06-21 09:45:11 +05302789 mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002790}
2791
Tomi Valkeinen65904152015-11-04 17:10:57 +02002792static void dispc_set_loadmode(enum omap_dss_load_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002793{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002794 REG_FLD_MOD(DISPC_CONFIG, mode, 2, 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002795}
2796
2797
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002798static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002799{
Sumit Semwal8613b002010-12-02 11:27:09 +00002800 dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002801}
2802
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002803static void dispc_mgr_set_trans_key(enum omap_channel ch,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002804 enum omap_dss_trans_key_type type,
2805 u32 trans_key)
2806{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302807 mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002808
Sumit Semwal8613b002010-12-02 11:27:09 +00002809 dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002810}
2811
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002812static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002813{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302814 mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002815}
Archit Taneja11354dd2011-09-26 11:47:29 +05302816
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002817static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch,
2818 bool enable)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002819{
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03002820 if (!dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002821 return;
2822
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002823 if (ch == OMAP_DSS_CHANNEL_LCD)
2824 REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18);
Sumit Semwal2a205f32010-12-02 11:27:12 +00002825 else if (ch == OMAP_DSS_CHANNEL_DIGIT)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002826 REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002827}
Archit Taneja11354dd2011-09-26 11:47:29 +05302828
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002829static void dispc_mgr_setup(struct dispc_device *dispc,
2830 enum omap_channel channel,
2831 const struct omap_overlay_manager_info *info)
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002832{
2833 dispc_mgr_set_default_color(channel, info->default_color);
2834 dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key);
2835 dispc_mgr_enable_trans_key(channel, info->trans_enabled);
2836 dispc_mgr_enable_alpha_fixed_zorder(channel,
2837 info->partial_alpha_enabled);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03002838 if (dispc_has_feature(FEAT_CPR)) {
Tomi Valkeinenc64dca42011-11-04 18:14:20 +02002839 dispc_mgr_enable_cpr(channel, info->cpr_enable);
2840 dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs);
2841 }
2842}
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002843
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002844static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002845{
2846 int code;
2847
2848 switch (data_lines) {
2849 case 12:
2850 code = 0;
2851 break;
2852 case 16:
2853 code = 1;
2854 break;
2855 case 18:
2856 code = 2;
2857 break;
2858 case 24:
2859 code = 3;
2860 break;
2861 default:
2862 BUG();
2863 return;
2864 }
2865
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302866 mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002867}
2868
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002869static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002870{
2871 u32 l;
Archit Taneja569969d2011-08-22 17:41:57 +05302872 int gpout0, gpout1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002873
2874 switch (mode) {
Archit Taneja569969d2011-08-22 17:41:57 +05302875 case DSS_IO_PAD_MODE_RESET:
2876 gpout0 = 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002877 gpout1 = 0;
2878 break;
Archit Taneja569969d2011-08-22 17:41:57 +05302879 case DSS_IO_PAD_MODE_RFBI:
2880 gpout0 = 1;
2881 gpout1 = 0;
2882 break;
2883 case DSS_IO_PAD_MODE_BYPASS:
2884 gpout0 = 1;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002885 gpout1 = 1;
2886 break;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002887 default:
2888 BUG();
2889 return;
2890 }
2891
Archit Taneja569969d2011-08-22 17:41:57 +05302892 l = dispc_read_reg(DISPC_CONTROL);
2893 l = FLD_MOD(l, gpout0, 15, 15);
2894 l = FLD_MOD(l, gpout1, 16, 16);
2895 dispc_write_reg(DISPC_CONTROL, l);
2896}
2897
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002898static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable)
Archit Taneja569969d2011-08-22 17:41:57 +05302899{
Chandrabhanu Mahapatraefa70b32012-06-21 11:07:44 +05302900 mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002901}
2902
Laurent Pinchart50638ae2018-02-13 14:00:42 +02002903static void dispc_mgr_set_lcd_config(struct dispc_device *dispc,
2904 enum omap_channel channel,
2905 const struct dss_lcd_mgr_config *config)
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002906{
2907 dispc_mgr_set_io_pad_mode(config->io_pad_mode);
2908
2909 dispc_mgr_enable_stallmode(channel, config->stallmode);
2910 dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck);
2911
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02002912 dispc_mgr_set_clock_div(dispc, channel, &config->clock_info);
Tomi Valkeinenfb2cec12012-09-12 13:30:39 +03002913
2914 dispc_mgr_set_tft_data_lines(channel, config->video_port_width);
2915
2916 dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity);
2917
2918 dispc_mgr_set_lcd_type_tft(channel);
2919}
2920
Archit Taneja8f366162012-04-16 12:53:44 +05302921static bool _dispc_mgr_size_ok(u16 width, u16 height)
2922{
Archit Taneja33b89922012-11-14 13:50:15 +05302923 return width <= dispc.feat->mgr_width_max &&
2924 height <= dispc.feat->mgr_height_max;
Archit Taneja8f366162012-04-16 12:53:44 +05302925}
2926
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03002927static bool _dispc_lcd_timings_ok(int hsync_len, int hfp, int hbp,
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002928 int vsw, int vfp, int vbp)
2929{
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03002930 if (hsync_len < 1 || hsync_len > dispc.feat->sw_max ||
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05302931 hfp < 1 || hfp > dispc.feat->hp_max ||
2932 hbp < 1 || hbp > dispc.feat->hp_max ||
2933 vsw < 1 || vsw > dispc.feat->sw_max ||
2934 vfp < 0 || vfp > dispc.feat->vp_max ||
2935 vbp < 0 || vbp > dispc.feat->vp_max)
2936 return false;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002937 return true;
2938}
2939
Archit Tanejaca5ca692013-03-26 19:15:22 +05302940static bool _dispc_mgr_pclk_ok(enum omap_channel channel,
2941 unsigned long pclk)
2942{
2943 if (dss_mgr_is_lcd(channel))
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05002944 return pclk <= dispc.feat->max_lcd_pclk;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302945 else
Andrew F. Davis0cac5b62016-07-01 09:27:21 -05002946 return pclk <= dispc.feat->max_tv_pclk;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302947}
2948
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02002949bool dispc_mgr_timings_ok(struct dispc_device *dispc, enum omap_channel channel,
2950 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002951{
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002952 if (!_dispc_mgr_size_ok(vm->hactive, vm->vactive))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002953 return false;
Archit Taneja8f366162012-04-16 12:53:44 +05302954
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002955 if (!_dispc_mgr_pclk_ok(channel, vm->pixelclock))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002956 return false;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302957
2958 if (dss_mgr_is_lcd(channel)) {
Tomi Valkeinenbeb83842014-06-05 11:35:10 +03002959 /* TODO: OMAP4+ supports interlace for LCD outputs */
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002960 if (vm->flags & DISPLAY_FLAGS_INTERLACED)
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002961 return false;
Tomi Valkeinenbeb83842014-06-05 11:35:10 +03002962
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002963 if (!_dispc_lcd_timings_ok(vm->hsync_len,
2964 vm->hfront_porch, vm->hback_porch,
2965 vm->vsync_len, vm->vfront_porch,
2966 vm->vback_porch))
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002967 return false;
Archit Tanejaca5ca692013-03-26 19:15:22 +05302968 }
Archit Taneja8f366162012-04-16 12:53:44 +05302969
Tomi Valkeineneadd33b2014-06-05 11:36:08 +03002970 return true;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002971}
2972
Peter Ujfalusi3b592932016-09-22 14:06:56 +03002973static void _dispc_mgr_set_lcd_timings(enum omap_channel channel,
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002974 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002975{
Archit Taneja655e2942012-06-21 10:37:43 +05302976 u32 timing_h, timing_v, l;
Tomi Valkeinened351882014-10-02 17:58:49 +00002977 bool onoff, rf, ipc, vs, hs, de;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002978
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002979 timing_h = FLD_VAL(vm->hsync_len - 1, dispc.feat->sw_start, 0) |
2980 FLD_VAL(vm->hfront_porch - 1, dispc.feat->fp_start, 8) |
2981 FLD_VAL(vm->hback_porch - 1, dispc.feat->bp_start, 20);
2982 timing_v = FLD_VAL(vm->vsync_len - 1, dispc.feat->sw_start, 0) |
2983 FLD_VAL(vm->vfront_porch, dispc.feat->fp_start, 8) |
2984 FLD_VAL(vm->vback_porch, dispc.feat->bp_start, 20);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02002985
Sumit Semwal64ba4f72010-12-02 11:27:10 +00002986 dispc_write_reg(DISPC_TIMING_H(channel), timing_h);
2987 dispc_write_reg(DISPC_TIMING_V(channel), timing_v);
Archit Taneja655e2942012-06-21 10:37:43 +05302988
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002989 if (vm->flags & DISPLAY_FLAGS_VSYNC_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00002990 vs = false;
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03002991 else
2992 vs = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00002993
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002994 if (vm->flags & DISPLAY_FLAGS_HSYNC_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00002995 hs = false;
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03002996 else
2997 hs = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00002998
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03002999 if (vm->flags & DISPLAY_FLAGS_DE_HIGH)
Tomi Valkeinened351882014-10-02 17:58:49 +00003000 de = false;
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +03003001 else
3002 de = true;
Tomi Valkeinened351882014-10-02 17:58:49 +00003003
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003004 if (vm->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
Archit Taneja655e2942012-06-21 10:37:43 +05303005 ipc = false;
Peter Ujfalusif149e172016-09-22 14:07:00 +03003006 else
Archit Taneja655e2942012-06-21 10:37:43 +05303007 ipc = true;
Archit Taneja655e2942012-06-21 10:37:43 +05303008
Tomi Valkeinen7a163602014-10-02 17:58:48 +00003009 /* always use the 'rf' setting */
3010 onoff = true;
3011
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003012 if (vm->flags & DISPLAY_FLAGS_SYNC_POSEDGE)
Archit Taneja655e2942012-06-21 10:37:43 +05303013 rf = true;
Peter Ujfalusid34afb72016-09-22 14:07:01 +03003014 else
3015 rf = false;
Archit Taneja655e2942012-06-21 10:37:43 +05303016
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03003017 l = FLD_VAL(onoff, 17, 17) |
3018 FLD_VAL(rf, 16, 16) |
Tomi Valkeinened351882014-10-02 17:58:49 +00003019 FLD_VAL(de, 15, 15) |
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03003020 FLD_VAL(ipc, 14, 14) |
Tomi Valkeinened351882014-10-02 17:58:49 +00003021 FLD_VAL(hs, 13, 13) |
3022 FLD_VAL(vs, 12, 12);
Tomi Valkeinend80e02e2014-04-25 11:46:16 +03003023
Tomi Valkeinene5f80912015-10-21 13:08:59 +03003024 /* always set ALIGN bit when available */
3025 if (dispc.feat->supports_sync_align)
3026 l |= (1 << 18);
3027
Archit Taneja655e2942012-06-21 10:37:43 +05303028 dispc_write_reg(DISPC_POL_FREQ(channel), l);
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00003029
3030 if (dispc.syscon_pol) {
3031 const int shifts[] = {
3032 [OMAP_DSS_CHANNEL_LCD] = 0,
3033 [OMAP_DSS_CHANNEL_LCD2] = 1,
3034 [OMAP_DSS_CHANNEL_LCD3] = 2,
3035 };
3036
3037 u32 mask, val;
3038
3039 mask = (1 << 0) | (1 << 3) | (1 << 6);
3040 val = (rf << 0) | (ipc << 3) | (onoff << 6);
3041
3042 mask <<= 16 + shifts[channel];
3043 val <<= 16 + shifts[channel];
3044
3045 regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
3046 mask, val);
3047 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003048}
3049
Tomi Valkeinen956d4f92016-11-23 13:23:42 +02003050static int vm_flag_to_int(enum display_flags flags, enum display_flags high,
3051 enum display_flags low)
3052{
3053 if (flags & high)
3054 return 1;
3055 if (flags & low)
3056 return -1;
3057 return 0;
3058}
3059
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003060/* change name to mode? */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003061static void dispc_mgr_set_timings(struct dispc_device *dispc,
3062 enum omap_channel channel,
3063 const struct videomode *vm)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003064{
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02003065 unsigned int xtot, ytot;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003066 unsigned long ht, vt;
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003067 struct videomode t = *vm;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003068
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003069 DSSDBG("channel %d xres %u yres %u\n", channel, t.hactive, t.vactive);
Archit Tanejac51d9212012-04-16 12:53:43 +05303070
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003071 if (!dispc_mgr_timings_ok(dispc, channel, &t)) {
Archit Taneja8f366162012-04-16 12:53:44 +05303072 BUG();
Tomi Valkeinenc6eee962012-05-18 11:47:02 +03003073 return;
3074 }
Archit Tanejac51d9212012-04-16 12:53:43 +05303075
Archit Tanejadd88b7a2012-06-29 14:41:30 +05303076 if (dss_mgr_is_lcd(channel)) {
Peter Ujfalusi3b592932016-09-22 14:06:56 +03003077 _dispc_mgr_set_lcd_timings(channel, &t);
Archit Tanejac51d9212012-04-16 12:53:43 +05303078
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03003079 xtot = t.hactive + t.hfront_porch + t.hsync_len + t.hback_porch;
Peter Ujfalusi458540c2016-09-22 14:06:53 +03003080 ytot = t.vactive + t.vfront_porch + t.vsync_len + t.vback_porch;
Archit Tanejac51d9212012-04-16 12:53:43 +05303081
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003082 ht = vm->pixelclock / xtot;
3083 vt = vm->pixelclock / xtot / ytot;
Archit Tanejac51d9212012-04-16 12:53:43 +05303084
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03003085 DSSDBG("pck %lu\n", vm->pixelclock);
Peter Ujfalusi4dc22502016-09-22 14:06:48 +03003086 DSSDBG("hsync_len %d hfp %d hbp %d vsw %d vfp %d vbp %d\n",
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03003087 t.hsync_len, t.hfront_porch, t.hback_porch,
Peter Ujfalusi458540c2016-09-22 14:06:53 +03003088 t.vsync_len, t.vfront_porch, t.vback_porch);
Archit Taneja655e2942012-06-21 10:37:43 +05303089 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 +02003090 vm_flag_to_int(t.flags, DISPLAY_FLAGS_VSYNC_HIGH, DISPLAY_FLAGS_VSYNC_LOW),
3091 vm_flag_to_int(t.flags, DISPLAY_FLAGS_HSYNC_HIGH, DISPLAY_FLAGS_HSYNC_LOW),
3092 vm_flag_to_int(t.flags, DISPLAY_FLAGS_PIXDATA_POSEDGE, DISPLAY_FLAGS_PIXDATA_NEGEDGE),
3093 vm_flag_to_int(t.flags, DISPLAY_FLAGS_DE_HIGH, DISPLAY_FLAGS_DE_LOW),
3094 vm_flag_to_int(t.flags, DISPLAY_FLAGS_SYNC_POSEDGE, DISPLAY_FLAGS_SYNC_NEGEDGE));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003095
Archit Tanejac51d9212012-04-16 12:53:43 +05303096 DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt);
Archit Taneja2aefad42012-05-18 14:36:54 +05303097 } else {
Peter Ujfalusi53058292016-09-22 14:06:55 +03003098 if (t.flags & DISPLAY_FLAGS_INTERLACED)
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003099 t.vactive /= 2;
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02003100
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003101 if (dispc->feat->supports_double_pixel)
Peter Ujfalusi531efb32016-09-22 14:06:59 +03003102 REG_FLD_MOD(DISPC_CONTROL,
3103 !!(t.flags & DISPLAY_FLAGS_DOUBLECLK),
3104 19, 17);
Archit Tanejac51d9212012-04-16 12:53:43 +05303105 }
Archit Taneja8f366162012-04-16 12:53:44 +05303106
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03003107 dispc_mgr_set_size(channel, t.hactive, t.vactive);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003108}
3109
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003110static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div,
Sumit Semwalff1b2cd2010-12-02 11:27:11 +00003111 u16 pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003112{
3113 BUG_ON(lck_div < 1);
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003114 BUG_ON(pck_div < 1);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003115
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003116 dispc_write_reg(DISPC_DIVISORo(channel),
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003117 FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0));
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003118
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003119 if (!dispc_has_feature(FEAT_CORE_CLK_DIV) &&
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003120 channel == OMAP_DSS_CHANNEL_LCD)
3121 dispc.core_clk_rate = dispc_fclk_rate() / lck_div;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003122}
3123
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003124static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
Sumit Semwal2a205f32010-12-02 11:27:12 +00003125 int *pck_div)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003126{
3127 u32 l;
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003128 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003129 *lck_div = FLD_GET(l, 23, 16);
3130 *pck_div = FLD_GET(l, 7, 0);
3131}
3132
Tomi Valkeinen65904152015-11-04 17:10:57 +02003133static unsigned long dispc_fclk_rate(void)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003134{
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003135 unsigned long r;
3136 enum dss_clk_source src;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003137
Laurent Pinchart3cc62aa2018-02-13 14:00:25 +02003138 src = dss_get_dispc_clk_source(dispc.dss);
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003139
3140 if (src == DSS_CLK_SRC_FCK) {
Laurent Pinchart60f9c592018-02-13 14:00:26 +02003141 r = dss_get_dispc_clk_rate(dispc.dss);
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003142 } else {
3143 struct dss_pll *pll;
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02003144 unsigned int clkout_idx;
Tomi Valkeinen93550922014-12-31 11:25:48 +02003145
Laurent Pinchart798957a2018-02-13 14:00:30 +02003146 pll = dss_pll_find_by_src(dispc.dss, src);
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003147 clkout_idx = dss_pll_get_clkout_idx_for_src(src);
Tomi Valkeinen93550922014-12-31 11:25:48 +02003148
Tomi Valkeinenef03b402016-05-18 13:52:14 +03003149 r = pll->cinfo.clkout[clkout_idx];
Taneja, Archit66534e82011-03-08 05:50:34 -06003150 }
3151
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003152 return r;
3153}
3154
Tomi Valkeinen65904152015-11-04 17:10:57 +02003155static unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003156{
3157 int lcd;
3158 unsigned long r;
Tomi Valkeinen01575772016-05-17 16:08:34 +03003159 enum dss_clk_source src;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003160
Tomi Valkeinen01575772016-05-17 16:08:34 +03003161 /* for TV, LCLK rate is the FCLK rate */
3162 if (!dss_mgr_is_lcd(channel))
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003163 return dispc_fclk_rate();
Tomi Valkeinen01575772016-05-17 16:08:34 +03003164
Laurent Pinchart3cc62aa2018-02-13 14:00:25 +02003165 src = dss_get_lcd_clk_source(dispc.dss, channel);
Tomi Valkeinen01575772016-05-17 16:08:34 +03003166
3167 if (src == DSS_CLK_SRC_FCK) {
Laurent Pinchart60f9c592018-02-13 14:00:26 +02003168 r = dss_get_dispc_clk_rate(dispc.dss);
Tomi Valkeinen01575772016-05-17 16:08:34 +03003169 } else {
3170 struct dss_pll *pll;
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02003171 unsigned int clkout_idx;
Tomi Valkeinen01575772016-05-17 16:08:34 +03003172
Laurent Pinchart798957a2018-02-13 14:00:30 +02003173 pll = dss_pll_find_by_src(dispc.dss, src);
Tomi Valkeinen01575772016-05-17 16:08:34 +03003174 clkout_idx = dss_pll_get_clkout_idx_for_src(src);
3175
3176 r = pll->cinfo.clkout[clkout_idx];
Taneja, Architea751592011-03-08 05:50:35 -06003177 }
Tomi Valkeinen01575772016-05-17 16:08:34 +03003178
3179 lcd = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3180
3181 return r / lcd;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003182}
3183
Tomi Valkeinen65904152015-11-04 17:10:57 +02003184static unsigned long dispc_mgr_pclk_rate(enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003185{
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003186 unsigned long r;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003187
Archit Tanejadd88b7a2012-06-29 14:41:30 +05303188 if (dss_mgr_is_lcd(channel)) {
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303189 int pcd;
3190 u32 l;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003191
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303192 l = dispc_read_reg(DISPC_DIVISORo(channel));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003193
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303194 pcd = FLD_GET(l, 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003195
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303196 r = dispc_mgr_lclk_rate(channel);
3197
3198 return r / pcd;
3199 } else {
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003200 return dispc.tv_pclk_rate;
Archit Tanejac3dc6a72011-09-13 18:28:41 +05303201 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003202}
3203
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003204void dispc_set_tv_pclk(struct dispc_device *dispc, unsigned long pclk)
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003205{
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003206 dispc->tv_pclk_rate = pclk;
Tomi Valkeinen5391e872013-05-16 10:44:13 +03003207}
3208
Tomi Valkeinen65904152015-11-04 17:10:57 +02003209static unsigned long dispc_core_clk_rate(void)
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05303210{
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003211 return dispc.core_clk_rate;
Chandrabhanu Mahapatra8b53d992012-04-23 12:16:50 +05303212}
3213
Jyri Sarha864050c2017-03-24 16:47:52 +02003214static unsigned long dispc_plane_pclk_rate(enum omap_plane_id plane)
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303215{
Tomi Valkeinen251886d2012-11-15 13:20:02 +02003216 enum omap_channel channel;
3217
3218 if (plane == OMAP_DSS_WB)
3219 return 0;
3220
3221 channel = dispc_ovl_get_channel_out(plane);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303222
3223 return dispc_mgr_pclk_rate(channel);
3224}
3225
Jyri Sarha864050c2017-03-24 16:47:52 +02003226static unsigned long dispc_plane_lclk_rate(enum omap_plane_id plane)
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303227{
Tomi Valkeinen251886d2012-11-15 13:20:02 +02003228 enum omap_channel channel;
3229
3230 if (plane == OMAP_DSS_WB)
3231 return 0;
3232
3233 channel = dispc_ovl_get_channel_out(plane);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303234
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003235 return dispc_mgr_lclk_rate(channel);
Archit Taneja3e8a6ff2012-09-26 16:58:52 +05303236}
Tomi Valkeinenc31cba82012-10-23 11:50:10 +03003237
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303238static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003239{
3240 int lcd, pcd;
Tomi Valkeinendc0352d2016-05-17 13:45:09 +03003241 enum dss_clk_source lcd_clk_src;
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303242
3243 seq_printf(s, "- %s -\n", mgr_desc[channel].name);
3244
Laurent Pinchart3cc62aa2018-02-13 14:00:25 +02003245 lcd_clk_src = dss_get_lcd_clk_source(dispc.dss, channel);
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303246
Tomi Valkeinen557a1542016-05-17 13:49:18 +03003247 seq_printf(s, "%s clk source = %s\n", mgr_desc[channel].name,
Tomi Valkeinen407bd562016-05-17 13:50:55 +03003248 dss_get_clk_source_name(lcd_clk_src));
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303249
3250 dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd);
3251
3252 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3253 dispc_mgr_lclk_rate(channel), lcd);
3254 seq_printf(s, "pck\t\t%-16lupck div\t%u\n",
3255 dispc_mgr_pclk_rate(channel), pcd);
3256}
3257
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003258void dispc_dump_clocks(struct dispc_device *dispc, struct seq_file *s)
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303259{
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003260 enum dss_clk_source dispc_clk_src;
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303261 int lcd;
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003262 u32 l;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003263
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003264 if (dispc_runtime_get(dispc))
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003265 return;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003266
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003267 seq_printf(s, "- DISPC -\n");
3268
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003269 dispc_clk_src = dss_get_dispc_clk_source(dispc->dss);
Tomi Valkeinen557a1542016-05-17 13:49:18 +03003270 seq_printf(s, "dispc fclk source = %s\n",
Tomi Valkeinen407bd562016-05-17 13:50:55 +03003271 dss_get_clk_source_name(dispc_clk_src));
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003272
3273 seq_printf(s, "fck\t\t%-16lu\n", dispc_fclk_rate());
Sumit Semwal2a205f32010-12-02 11:27:12 +00003274
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003275 if (dispc_has_feature(FEAT_CORE_CLK_DIV)) {
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003276 seq_printf(s, "- DISPC-CORE-CLK -\n");
3277 l = dispc_read_reg(DISPC_DIVISOR);
3278 lcd = FLD_GET(l, 23, 16);
3279
3280 seq_printf(s, "lck\t\t%-16lulck div\t%u\n",
3281 (dispc_fclk_rate()/lcd), lcd);
3282 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003283
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303284 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD);
Taneja, Architea751592011-03-08 05:50:35 -06003285
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003286 if (dispc_has_feature(FEAT_MGR_LCD2))
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303287 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003288 if (dispc_has_feature(FEAT_MGR_LCD3))
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303289 dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03003290
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003291 dispc_runtime_put(dispc);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003292}
3293
Laurent Pinchartf33656e2018-02-13 14:00:29 +02003294static int dispc_dump_regs(struct seq_file *s, void *p)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003295{
Archit Taneja4dd2da12011-08-05 19:06:01 +05303296 int i, j;
3297 const char *mgr_names[] = {
3298 [OMAP_DSS_CHANNEL_LCD] = "LCD",
3299 [OMAP_DSS_CHANNEL_DIGIT] = "TV",
3300 [OMAP_DSS_CHANNEL_LCD2] = "LCD2",
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303301 [OMAP_DSS_CHANNEL_LCD3] = "LCD3",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303302 };
3303 const char *ovl_names[] = {
3304 [OMAP_DSS_GFX] = "GFX",
3305 [OMAP_DSS_VIDEO1] = "VID1",
3306 [OMAP_DSS_VIDEO2] = "VID2",
Archit Tanejab8c095b2011-09-13 18:20:33 +05303307 [OMAP_DSS_VIDEO3] = "VID3",
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003308 [OMAP_DSS_WB] = "WB",
Archit Taneja4dd2da12011-08-05 19:06:01 +05303309 };
3310 const char **p_names;
3311
Archit Taneja9b372c22011-05-06 11:45:49 +05303312#define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r))
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003313
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003314 if (dispc_runtime_get(&dispc))
Laurent Pinchartf33656e2018-02-13 14:00:29 +02003315 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003316
Archit Taneja5010be82011-08-05 19:06:00 +05303317 /* DISPC common registers */
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003318 DUMPREG(DISPC_REVISION);
3319 DUMPREG(DISPC_SYSCONFIG);
3320 DUMPREG(DISPC_SYSSTATUS);
3321 DUMPREG(DISPC_IRQSTATUS);
3322 DUMPREG(DISPC_IRQENABLE);
3323 DUMPREG(DISPC_CONTROL);
3324 DUMPREG(DISPC_CONFIG);
3325 DUMPREG(DISPC_CAPABLE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003326 DUMPREG(DISPC_LINE_STATUS);
3327 DUMPREG(DISPC_LINE_NUMBER);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003328 if (dispc_has_feature(FEAT_ALPHA_FIXED_ZORDER) ||
3329 dispc_has_feature(FEAT_ALPHA_FREE_ZORDER))
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003330 DUMPREG(DISPC_GLOBAL_ALPHA);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003331 if (dispc_has_feature(FEAT_MGR_LCD2)) {
Sumit Semwal2a205f32010-12-02 11:27:12 +00003332 DUMPREG(DISPC_CONTROL2);
3333 DUMPREG(DISPC_CONFIG2);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003334 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003335 if (dispc_has_feature(FEAT_MGR_LCD3)) {
Chandrabhanu Mahapatra6f1891f2012-06-21 11:23:56 +05303336 DUMPREG(DISPC_CONTROL3);
3337 DUMPREG(DISPC_CONFIG3);
3338 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003339 if (dispc_has_feature(FEAT_MFLAG))
Tomi Valkeinen29fceee2013-11-14 11:38:25 +02003340 DUMPREG(DISPC_GLOBAL_MFLAG_ATTRIBUTE);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003341
Archit Taneja5010be82011-08-05 19:06:00 +05303342#undef DUMPREG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003343
Archit Taneja5010be82011-08-05 19:06:00 +05303344#define DISPC_REG(i, name) name(i)
Archit Taneja4dd2da12011-08-05 19:06:01 +05303345#define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \
Tomi Valkeinen311d5ce2012-09-28 13:58:14 +03003346 (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303347 dispc_read_reg(DISPC_REG(i, r)))
3348
Archit Taneja4dd2da12011-08-05 19:06:01 +05303349 p_names = mgr_names;
Archit Taneja5010be82011-08-05 19:06:00 +05303350
Archit Taneja4dd2da12011-08-05 19:06:01 +05303351 /* DISPC channel specific registers */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003352 for (i = 0; i < dispc_get_num_mgrs(&dispc); i++) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303353 DUMPREG(i, DISPC_DEFAULT_COLOR);
3354 DUMPREG(i, DISPC_TRANS_COLOR);
3355 DUMPREG(i, DISPC_SIZE_MGR);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003356
Archit Taneja4dd2da12011-08-05 19:06:01 +05303357 if (i == OMAP_DSS_CHANNEL_DIGIT)
3358 continue;
Archit Taneja5010be82011-08-05 19:06:00 +05303359
Archit Taneja4dd2da12011-08-05 19:06:01 +05303360 DUMPREG(i, DISPC_TIMING_H);
3361 DUMPREG(i, DISPC_TIMING_V);
3362 DUMPREG(i, DISPC_POL_FREQ);
3363 DUMPREG(i, DISPC_DIVISORo);
Archit Taneja5010be82011-08-05 19:06:00 +05303364
Archit Taneja4dd2da12011-08-05 19:06:01 +05303365 DUMPREG(i, DISPC_DATA_CYCLE1);
3366 DUMPREG(i, DISPC_DATA_CYCLE2);
3367 DUMPREG(i, DISPC_DATA_CYCLE3);
Sumit Semwal2a205f32010-12-02 11:27:12 +00003368
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003369 if (dispc_has_feature(FEAT_CPR)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303370 DUMPREG(i, DISPC_CPR_COEF_R);
3371 DUMPREG(i, DISPC_CPR_COEF_G);
3372 DUMPREG(i, DISPC_CPR_COEF_B);
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003373 }
Sumit Semwal2a205f32010-12-02 11:27:12 +00003374 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003375
Archit Taneja4dd2da12011-08-05 19:06:01 +05303376 p_names = ovl_names;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003377
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003378 for (i = 0; i < dispc_get_num_ovls(&dispc); i++) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303379 DUMPREG(i, DISPC_OVL_BA0);
3380 DUMPREG(i, DISPC_OVL_BA1);
3381 DUMPREG(i, DISPC_OVL_POSITION);
3382 DUMPREG(i, DISPC_OVL_SIZE);
3383 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3384 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3385 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3386 DUMPREG(i, DISPC_OVL_ROW_INC);
3387 DUMPREG(i, DISPC_OVL_PIXEL_INC);
Tomi Valkeinenaba837a2014-09-29 20:46:16 +00003388
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003389 if (dispc_has_feature(FEAT_PRELOAD))
Archit Taneja4dd2da12011-08-05 19:06:01 +05303390 DUMPREG(i, DISPC_OVL_PRELOAD);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003391 if (dispc_has_feature(FEAT_MFLAG))
Tomi Valkeinenaba837a2014-09-29 20:46:16 +00003392 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003393
Archit Taneja4dd2da12011-08-05 19:06:01 +05303394 if (i == OMAP_DSS_GFX) {
3395 DUMPREG(i, DISPC_OVL_WINDOW_SKIP);
3396 DUMPREG(i, DISPC_OVL_TABLE_BA);
3397 continue;
3398 }
3399
3400 DUMPREG(i, DISPC_OVL_FIR);
3401 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3402 DUMPREG(i, DISPC_OVL_ACCU0);
3403 DUMPREG(i, DISPC_OVL_ACCU1);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003404 if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303405 DUMPREG(i, DISPC_OVL_BA0_UV);
3406 DUMPREG(i, DISPC_OVL_BA1_UV);
3407 DUMPREG(i, DISPC_OVL_FIR2);
3408 DUMPREG(i, DISPC_OVL_ACCU2_0);
3409 DUMPREG(i, DISPC_OVL_ACCU2_1);
3410 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003411 if (dispc_has_feature(FEAT_ATTR2))
Archit Taneja4dd2da12011-08-05 19:06:01 +05303412 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
Archit Taneja5010be82011-08-05 19:06:00 +05303413 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003414
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02003415 if (dispc.feat->has_writeback) {
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003416 i = OMAP_DSS_WB;
3417 DUMPREG(i, DISPC_OVL_BA0);
3418 DUMPREG(i, DISPC_OVL_BA1);
3419 DUMPREG(i, DISPC_OVL_SIZE);
3420 DUMPREG(i, DISPC_OVL_ATTRIBUTES);
3421 DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD);
3422 DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS);
3423 DUMPREG(i, DISPC_OVL_ROW_INC);
3424 DUMPREG(i, DISPC_OVL_PIXEL_INC);
3425
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003426 if (dispc_has_feature(FEAT_MFLAG))
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003427 DUMPREG(i, DISPC_OVL_MFLAG_THRESHOLD);
3428
3429 DUMPREG(i, DISPC_OVL_FIR);
3430 DUMPREG(i, DISPC_OVL_PICTURE_SIZE);
3431 DUMPREG(i, DISPC_OVL_ACCU0);
3432 DUMPREG(i, DISPC_OVL_ACCU1);
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003433 if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003434 DUMPREG(i, DISPC_OVL_BA0_UV);
3435 DUMPREG(i, DISPC_OVL_BA1_UV);
3436 DUMPREG(i, DISPC_OVL_FIR2);
3437 DUMPREG(i, DISPC_OVL_ACCU2_0);
3438 DUMPREG(i, DISPC_OVL_ACCU2_1);
3439 }
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003440 if (dispc_has_feature(FEAT_ATTR2))
Tomi Valkeinen06c525f2015-11-04 17:10:42 +02003441 DUMPREG(i, DISPC_OVL_ATTRIBUTES2);
3442 }
3443
Archit Taneja5010be82011-08-05 19:06:00 +05303444#undef DISPC_REG
3445#undef DUMPREG
3446
3447#define DISPC_REG(plane, name, i) name(plane, i)
3448#define DUMPREG(plane, name, i) \
Archit Taneja4dd2da12011-08-05 19:06:01 +05303449 seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \
Tomi Valkeinen311d5ce2012-09-28 13:58:14 +03003450 (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \
Archit Taneja5010be82011-08-05 19:06:00 +05303451 dispc_read_reg(DISPC_REG(plane, name, i)))
3452
Archit Taneja4dd2da12011-08-05 19:06:01 +05303453 /* Video pipeline coefficient registers */
Archit Taneja5010be82011-08-05 19:06:00 +05303454
Archit Taneja4dd2da12011-08-05 19:06:01 +05303455 /* start from OMAP_DSS_VIDEO1 */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003456 for (i = 1; i < dispc_get_num_ovls(&dispc); i++) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303457 for (j = 0; j < 8; j++)
3458 DUMPREG(i, DISPC_OVL_FIR_COEF_H, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303459
Archit Taneja4dd2da12011-08-05 19:06:01 +05303460 for (j = 0; j < 8; j++)
3461 DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j);
Archit Taneja5010be82011-08-05 19:06:00 +05303462
Archit Taneja4dd2da12011-08-05 19:06:01 +05303463 for (j = 0; j < 5; j++)
3464 DUMPREG(i, DISPC_OVL_CONV_COEF, j);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003465
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003466 if (dispc_has_feature(FEAT_FIR_COEF_V)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303467 for (j = 0; j < 8; j++)
3468 DUMPREG(i, DISPC_OVL_FIR_COEF_V, j);
3469 }
Amber Jainab5ca072011-05-19 19:47:53 +05303470
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003471 if (dispc_has_feature(FEAT_HANDLE_UV_SEPARATE)) {
Archit Taneja4dd2da12011-08-05 19:06:01 +05303472 for (j = 0; j < 8; j++)
3473 DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303474
Archit Taneja4dd2da12011-08-05 19:06:01 +05303475 for (j = 0; j < 8; j++)
3476 DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j);
Amber Jainab5ca072011-05-19 19:47:53 +05303477
Archit Taneja4dd2da12011-08-05 19:06:01 +05303478 for (j = 0; j < 8; j++)
3479 DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j);
3480 }
Tomi Valkeinen332e9d72011-05-27 14:22:16 +03003481 }
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003482
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003483 dispc_runtime_put(&dispc);
Archit Taneja5010be82011-08-05 19:06:00 +05303484
3485#undef DISPC_REG
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003486#undef DUMPREG
Laurent Pinchartf33656e2018-02-13 14:00:29 +02003487
3488 return 0;
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003489}
3490
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003491/* calculate clock rates using dividers in cinfo */
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003492int dispc_calc_clock_rates(struct dispc_device *dispc,
3493 unsigned long dispc_fclk_rate,
3494 struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003495{
3496 if (cinfo->lck_div > 255 || cinfo->lck_div == 0)
3497 return -EINVAL;
Tomi Valkeinen9eaaf202011-08-29 15:56:04 +03003498 if (cinfo->pck_div < 1 || cinfo->pck_div > 255)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003499 return -EINVAL;
3500
3501 cinfo->lck = dispc_fclk_rate / cinfo->lck_div;
3502 cinfo->pck = cinfo->lck / cinfo->pck_div;
3503
3504 return 0;
3505}
3506
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003507bool dispc_div_calc(struct dispc_device *dispc, unsigned long dispc_freq,
3508 unsigned long pck_min, unsigned long pck_max,
3509 dispc_div_calc_func func, void *data)
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003510{
3511 int lckd, lckd_start, lckd_stop;
3512 int pckd, pckd_start, pckd_stop;
3513 unsigned long pck, lck;
3514 unsigned long lck_max;
3515 unsigned long pckd_hw_min, pckd_hw_max;
Laurent Pinchartd11e5c82018-02-11 15:07:34 +02003516 unsigned int min_fck_per_pck;
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003517 unsigned long fck;
3518
3519#ifdef CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK
3520 min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK;
3521#else
3522 min_fck_per_pck = 0;
3523#endif
3524
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003525 pckd_hw_min = dispc->feat->min_pcd;
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03003526 pckd_hw_max = 255;
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003527
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003528 lck_max = dss_get_max_fck_rate(dispc->dss);
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003529
3530 pck_min = pck_min ? pck_min : 1;
3531 pck_max = pck_max ? pck_max : ULONG_MAX;
3532
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03003533 lckd_start = max(DIV_ROUND_UP(dispc_freq, lck_max), 1ul);
3534 lckd_stop = min(dispc_freq / pck_min, 255ul);
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003535
3536 for (lckd = lckd_start; lckd <= lckd_stop; ++lckd) {
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03003537 lck = dispc_freq / lckd;
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003538
3539 pckd_start = max(DIV_ROUND_UP(lck, pck_max), pckd_hw_min);
3540 pckd_stop = min(lck / pck_min, pckd_hw_max);
3541
3542 for (pckd = pckd_start; pckd <= pckd_stop; ++pckd) {
3543 pck = lck / pckd;
3544
3545 /*
3546 * For OMAP2/3 the DISPC fclk is the same as LCD's logic
3547 * clock, which means we're configuring DISPC fclk here
3548 * also. Thus we need to use the calculated lck. For
3549 * OMAP4+ the DISPC fclk is a separate clock.
3550 */
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003551 if (dispc_has_feature(FEAT_CORE_CLK_DIV))
Tomi Valkeinen7c284e62013-03-05 16:32:08 +02003552 fck = dispc_core_clk_rate();
3553 else
3554 fck = lck;
3555
3556 if (fck < pck * min_fck_per_pck)
3557 continue;
3558
3559 if (func(lckd, pckd, lck, pck, data))
3560 return true;
3561 }
3562 }
3563
3564 return false;
3565}
3566
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003567void dispc_mgr_set_clock_div(struct dispc_device *dispc,
3568 enum omap_channel channel,
3569 const struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003570{
3571 DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div);
3572 DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div);
3573
Tomi Valkeinen26d9dd02011-08-16 13:45:15 +03003574 dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003575}
3576
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003577int dispc_mgr_get_clock_div(struct dispc_device *dispc,
3578 enum omap_channel channel,
3579 struct dispc_clock_info *cinfo)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003580{
3581 unsigned long fck;
3582
3583 fck = dispc_fclk_rate();
3584
Murthy, Raghuveerce7fa5e2011-03-03 09:27:59 -06003585 cinfo->lck_div = REG_GET(DISPC_DIVISORo(channel), 23, 16);
3586 cinfo->pck_div = REG_GET(DISPC_DIVISORo(channel), 7, 0);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003587
3588 cinfo->lck = fck / cinfo->lck_div;
3589 cinfo->pck = cinfo->lck / cinfo->pck_div;
3590
3591 return 0;
3592}
3593
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003594static u32 dispc_read_irqstatus(struct dispc_device *dispc)
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003595{
3596 return dispc_read_reg(DISPC_IRQSTATUS);
3597}
3598
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003599static void dispc_clear_irqstatus(struct dispc_device *dispc, u32 mask)
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003600{
3601 dispc_write_reg(DISPC_IRQSTATUS, mask);
3602}
3603
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003604static void dispc_write_irqenable(struct dispc_device *dispc, u32 mask)
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003605{
3606 u32 old_mask = dispc_read_reg(DISPC_IRQENABLE);
3607
3608 /* clear the irqstatus for newly enabled irqs */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003609 dispc_clear_irqstatus(dispc, (mask ^ old_mask) & mask);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003610
3611 dispc_write_reg(DISPC_IRQENABLE, mask);
Tomi Valkeinen2e953d82017-02-20 13:18:38 +02003612
3613 /* flush posted write */
3614 dispc_read_reg(DISPC_IRQENABLE);
Tomi Valkeinen4e0397c2012-10-10 15:13:14 +03003615}
3616
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003617void dispc_enable_sidle(struct dispc_device *dispc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003618{
3619 REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */
3620}
3621
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02003622void dispc_disable_sidle(struct dispc_device *dispc)
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003623{
3624 REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */
3625}
3626
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003627static u32 dispc_mgr_gamma_size(struct dispc_device *dispc,
3628 enum omap_channel channel)
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003629{
3630 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3631
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003632 if (!dispc->feat->has_gamma_table)
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003633 return 0;
3634
3635 return gdesc->len;
3636}
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003637
3638static void dispc_mgr_write_gamma_table(enum omap_channel channel)
3639{
3640 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3641 u32 *table = dispc.gamma_table[channel];
3642 unsigned int i;
3643
3644 DSSDBG("%s: channel %d\n", __func__, channel);
3645
3646 for (i = 0; i < gdesc->len; ++i) {
3647 u32 v = table[i];
3648
3649 if (gdesc->has_index)
3650 v |= i << 24;
3651 else if (i == 0)
3652 v |= 1 << 31;
3653
3654 dispc_write_reg(gdesc->reg, v);
3655 }
3656}
3657
3658static void dispc_restore_gamma_tables(void)
3659{
3660 DSSDBG("%s()\n", __func__);
3661
3662 if (!dispc.feat->has_gamma_table)
3663 return;
3664
3665 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD);
3666
3667 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_DIGIT);
3668
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003669 if (dispc_has_feature(FEAT_MGR_LCD2))
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003670 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD2);
3671
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003672 if (dispc_has_feature(FEAT_MGR_LCD3))
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003673 dispc_mgr_write_gamma_table(OMAP_DSS_CHANNEL_LCD3);
3674}
3675
3676static const struct drm_color_lut dispc_mgr_gamma_default_lut[] = {
3677 { .red = 0, .green = 0, .blue = 0, },
3678 { .red = U16_MAX, .green = U16_MAX, .blue = U16_MAX, },
3679};
3680
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003681static void dispc_mgr_set_gamma(struct dispc_device *dispc,
3682 enum omap_channel channel,
3683 const struct drm_color_lut *lut,
3684 unsigned int length)
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003685{
3686 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003687 u32 *table = dispc->gamma_table[channel];
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003688 uint i;
3689
3690 DSSDBG("%s: channel %d, lut len %u, hw len %u\n", __func__,
3691 channel, length, gdesc->len);
3692
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003693 if (!dispc->feat->has_gamma_table)
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003694 return;
3695
3696 if (lut == NULL || length < 2) {
3697 lut = dispc_mgr_gamma_default_lut;
3698 length = ARRAY_SIZE(dispc_mgr_gamma_default_lut);
3699 }
3700
3701 for (i = 0; i < length - 1; ++i) {
3702 uint first = i * (gdesc->len - 1) / (length - 1);
3703 uint last = (i + 1) * (gdesc->len - 1) / (length - 1);
3704 uint w = last - first;
3705 u16 r, g, b;
3706 uint j;
3707
3708 if (w == 0)
3709 continue;
3710
3711 for (j = 0; j <= w; j++) {
3712 r = (lut[i].red * (w - j) + lut[i+1].red * j) / w;
3713 g = (lut[i].green * (w - j) + lut[i+1].green * j) / w;
3714 b = (lut[i].blue * (w - j) + lut[i+1].blue * j) / w;
3715
3716 r >>= 16 - gdesc->bits;
3717 g >>= 16 - gdesc->bits;
3718 b >>= 16 - gdesc->bits;
3719
3720 table[first + j] = (r << (gdesc->bits * 2)) |
3721 (g << gdesc->bits) | b;
3722 }
3723 }
3724
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003725 if (dispc->is_enabled)
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003726 dispc_mgr_write_gamma_table(channel);
3727}
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003728
3729static int dispc_init_gamma_tables(void)
3730{
3731 int channel;
3732
3733 if (!dispc.feat->has_gamma_table)
3734 return 0;
3735
3736 for (channel = 0; channel < ARRAY_SIZE(dispc.gamma_table); channel++) {
3737 const struct dispc_gamma_desc *gdesc = &mgr_desc[channel].gamma;
3738 u32 *gt;
3739
3740 if (channel == OMAP_DSS_CHANNEL_LCD2 &&
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003741 !dispc_has_feature(FEAT_MGR_LCD2))
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003742 continue;
3743
3744 if (channel == OMAP_DSS_CHANNEL_LCD3 &&
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003745 !dispc_has_feature(FEAT_MGR_LCD3))
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003746 continue;
3747
3748 gt = devm_kmalloc_array(&dispc.pdev->dev, gdesc->len,
3749 sizeof(u32), GFP_KERNEL);
3750 if (!gt)
3751 return -ENOMEM;
3752
3753 dispc.gamma_table[channel] = gt;
3754
Laurent Pinchart50638ae2018-02-13 14:00:42 +02003755 dispc_mgr_set_gamma(&dispc, channel, NULL, 0);
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003756 }
3757 return 0;
3758}
3759
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003760static void _omap_dispc_initial_config(void)
3761{
3762 u32 l;
3763
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003764 /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003765 if (dispc_has_feature(FEAT_CORE_CLK_DIV)) {
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003766 l = dispc_read_reg(DISPC_DIVISOR);
3767 /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */
3768 l = FLD_MOD(l, 1, 0, 0);
3769 l = FLD_MOD(l, 1, 23, 16);
3770 dispc_write_reg(DISPC_DIVISOR, l);
Tomi Valkeinen7b3926b2013-03-06 15:54:11 +02003771
3772 dispc.core_clk_rate = dispc_fclk_rate();
Murthy, Raghuveer0cf35df2011-03-03 09:28:00 -06003773 }
3774
Jyri Sarhaacc3a232016-06-07 15:09:15 +03003775 /* Use gamma table mode, instead of palette mode */
3776 if (dispc.feat->has_gamma_table)
3777 REG_FLD_MOD(DISPC_CONFIG, 1, 3, 3);
3778
3779 /* For older DSS versions (FEAT_FUNCGATED) this enables
3780 * func-clock auto-gating. For newer versions
3781 * (dispc.feat->has_gamma_table) this enables tv-out gamma tables.
3782 */
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003783 if (dispc_has_feature(FEAT_FUNCGATED) || dispc.feat->has_gamma_table)
Archit Taneja6ced40b2010-12-02 11:27:13 +00003784 REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9);
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003785
Archit Taneja6e5264b2012-09-11 12:04:47 +05303786 dispc_setup_color_conv_coef();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003787
3788 dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY);
3789
Tomi Valkeinen42a69612012-08-22 16:56:57 +03003790 dispc_init_fifos();
Tomi Valkeinen5ed8cf52011-06-21 09:35:36 +03003791
3792 dispc_configure_burst_sizes();
Archit Taneja54128702011-09-08 11:29:17 +05303793
3794 dispc_ovl_enable_zorder_planes();
Archit Tanejad0df9a22013-03-26 19:15:25 +05303795
3796 if (dispc.feat->mstandby_workaround)
3797 REG_FLD_MOD(DISPC_MSTANDBY_CTRL, 1, 0, 0);
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00003798
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003799 if (dispc_has_feature(FEAT_MFLAG))
Tomi Valkeinenc64aa3a2014-09-29 20:46:18 +00003800 dispc_init_mflag();
Tomi Valkeinen80c39712009-11-12 11:41:42 +02003801}
3802
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03003803static const enum dispc_feature_id omap2_dispc_features_list[] = {
3804 FEAT_LCDENABLEPOL,
3805 FEAT_LCDENABLESIGNAL,
3806 FEAT_PCKFREEENABLE,
3807 FEAT_FUNCGATED,
3808 FEAT_ROWREPEATENABLE,
3809 FEAT_RESIZECONF,
3810};
3811
3812static const enum dispc_feature_id omap3_dispc_features_list[] = {
3813 FEAT_LCDENABLEPOL,
3814 FEAT_LCDENABLESIGNAL,
3815 FEAT_PCKFREEENABLE,
3816 FEAT_FUNCGATED,
3817 FEAT_LINEBUFFERSPLIT,
3818 FEAT_ROWREPEATENABLE,
3819 FEAT_RESIZECONF,
3820 FEAT_CPR,
3821 FEAT_PRELOAD,
3822 FEAT_FIR_COEF_V,
3823 FEAT_ALPHA_FIXED_ZORDER,
3824 FEAT_FIFO_MERGE,
3825 FEAT_OMAP3_DSI_FIFO_BUG,
3826};
3827
3828static const enum dispc_feature_id am43xx_dispc_features_list[] = {
3829 FEAT_LCDENABLEPOL,
3830 FEAT_LCDENABLESIGNAL,
3831 FEAT_PCKFREEENABLE,
3832 FEAT_FUNCGATED,
3833 FEAT_LINEBUFFERSPLIT,
3834 FEAT_ROWREPEATENABLE,
3835 FEAT_RESIZECONF,
3836 FEAT_CPR,
3837 FEAT_PRELOAD,
3838 FEAT_FIR_COEF_V,
3839 FEAT_ALPHA_FIXED_ZORDER,
3840 FEAT_FIFO_MERGE,
3841};
3842
3843static const enum dispc_feature_id omap4_dispc_features_list[] = {
3844 FEAT_MGR_LCD2,
3845 FEAT_CORE_CLK_DIV,
3846 FEAT_HANDLE_UV_SEPARATE,
3847 FEAT_ATTR2,
3848 FEAT_CPR,
3849 FEAT_PRELOAD,
3850 FEAT_FIR_COEF_V,
3851 FEAT_ALPHA_FREE_ZORDER,
3852 FEAT_FIFO_MERGE,
3853 FEAT_BURST_2D,
3854};
3855
3856static const enum dispc_feature_id omap5_dispc_features_list[] = {
3857 FEAT_MGR_LCD2,
3858 FEAT_MGR_LCD3,
3859 FEAT_CORE_CLK_DIV,
3860 FEAT_HANDLE_UV_SEPARATE,
3861 FEAT_ATTR2,
3862 FEAT_CPR,
3863 FEAT_PRELOAD,
3864 FEAT_FIR_COEF_V,
3865 FEAT_ALPHA_FREE_ZORDER,
3866 FEAT_FIFO_MERGE,
3867 FEAT_BURST_2D,
3868 FEAT_MFLAG,
3869};
3870
Laurent Pinchart38dc0702017-08-05 01:44:08 +03003871static const struct dss_reg_field omap2_dispc_reg_fields[] = {
3872 [FEAT_REG_FIRHINC] = { 11, 0 },
3873 [FEAT_REG_FIRVINC] = { 27, 16 },
3874 [FEAT_REG_FIFOLOWTHRESHOLD] = { 8, 0 },
3875 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 24, 16 },
3876 [FEAT_REG_FIFOSIZE] = { 8, 0 },
3877 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
3878 [FEAT_REG_VERTICALACCU] = { 25, 16 },
3879};
3880
3881static const struct dss_reg_field omap3_dispc_reg_fields[] = {
3882 [FEAT_REG_FIRHINC] = { 12, 0 },
3883 [FEAT_REG_FIRVINC] = { 28, 16 },
3884 [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
3885 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
3886 [FEAT_REG_FIFOSIZE] = { 10, 0 },
3887 [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
3888 [FEAT_REG_VERTICALACCU] = { 25, 16 },
3889};
3890
3891static const struct dss_reg_field omap4_dispc_reg_fields[] = {
3892 [FEAT_REG_FIRHINC] = { 12, 0 },
3893 [FEAT_REG_FIRVINC] = { 28, 16 },
3894 [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 },
3895 [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 },
3896 [FEAT_REG_FIFOSIZE] = { 15, 0 },
3897 [FEAT_REG_HORIZONTALACCU] = { 10, 0 },
3898 [FEAT_REG_VERTICALACCU] = { 26, 16 },
3899};
3900
Laurent Pinchartfcd41882017-08-05 01:44:05 +03003901static const enum omap_overlay_caps omap2_dispc_overlay_caps[] = {
3902 /* OMAP_DSS_GFX */
3903 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
3904
3905 /* OMAP_DSS_VIDEO1 */
3906 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
3907 OMAP_DSS_OVL_CAP_REPLICATION,
3908
3909 /* OMAP_DSS_VIDEO2 */
3910 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
3911 OMAP_DSS_OVL_CAP_REPLICATION,
3912};
3913
3914static const enum omap_overlay_caps omap3430_dispc_overlay_caps[] = {
3915 /* OMAP_DSS_GFX */
3916 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS |
3917 OMAP_DSS_OVL_CAP_REPLICATION,
3918
3919 /* OMAP_DSS_VIDEO1 */
3920 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
3921 OMAP_DSS_OVL_CAP_REPLICATION,
3922
3923 /* OMAP_DSS_VIDEO2 */
3924 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
3925 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
3926};
3927
3928static const enum omap_overlay_caps omap3630_dispc_overlay_caps[] = {
3929 /* OMAP_DSS_GFX */
3930 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
3931 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
3932
3933 /* OMAP_DSS_VIDEO1 */
3934 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS |
3935 OMAP_DSS_OVL_CAP_REPLICATION,
3936
3937 /* OMAP_DSS_VIDEO2 */
3938 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
3939 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS |
3940 OMAP_DSS_OVL_CAP_REPLICATION,
3941};
3942
3943static const enum omap_overlay_caps omap4_dispc_overlay_caps[] = {
3944 /* OMAP_DSS_GFX */
3945 OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA |
3946 OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS |
3947 OMAP_DSS_OVL_CAP_REPLICATION,
3948
3949 /* OMAP_DSS_VIDEO1 */
3950 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
3951 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
3952 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
3953
3954 /* OMAP_DSS_VIDEO2 */
3955 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
3956 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
3957 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
3958
3959 /* OMAP_DSS_VIDEO3 */
3960 OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA |
3961 OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER |
3962 OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION,
3963};
3964
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03003965#define COLOR_ARRAY(arr...) (const u32[]) { arr, 0 }
3966
3967static const u32 *omap2_dispc_supported_color_modes[] = {
3968
3969 /* OMAP_DSS_GFX */
3970 COLOR_ARRAY(
3971 DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565,
3972 DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888),
3973
3974 /* OMAP_DSS_VIDEO1 */
3975 COLOR_ARRAY(
3976 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
3977 DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
3978 DRM_FORMAT_UYVY),
3979
3980 /* OMAP_DSS_VIDEO2 */
3981 COLOR_ARRAY(
3982 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
3983 DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
3984 DRM_FORMAT_UYVY),
3985};
3986
3987static const u32 *omap3_dispc_supported_color_modes[] = {
3988 /* OMAP_DSS_GFX */
3989 COLOR_ARRAY(
3990 DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
3991 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
3992 DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888,
3993 DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888),
3994
3995 /* OMAP_DSS_VIDEO1 */
3996 COLOR_ARRAY(
3997 DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB888,
3998 DRM_FORMAT_RGBX4444, DRM_FORMAT_RGB565,
3999 DRM_FORMAT_YUYV, DRM_FORMAT_UYVY),
4000
4001 /* OMAP_DSS_VIDEO2 */
4002 COLOR_ARRAY(
4003 DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
4004 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
4005 DRM_FORMAT_RGB888, DRM_FORMAT_YUYV,
4006 DRM_FORMAT_UYVY, DRM_FORMAT_ARGB8888,
4007 DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888),
4008};
4009
4010static const u32 *omap4_dispc_supported_color_modes[] = {
4011 /* OMAP_DSS_GFX */
4012 COLOR_ARRAY(
4013 DRM_FORMAT_RGBX4444, DRM_FORMAT_ARGB4444,
4014 DRM_FORMAT_RGB565, DRM_FORMAT_XRGB8888,
4015 DRM_FORMAT_RGB888, DRM_FORMAT_ARGB8888,
4016 DRM_FORMAT_RGBA8888, DRM_FORMAT_RGBX8888,
4017 DRM_FORMAT_ARGB1555, DRM_FORMAT_XRGB4444,
4018 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB1555),
4019
4020 /* OMAP_DSS_VIDEO1 */
4021 COLOR_ARRAY(
4022 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
4023 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
4024 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
4025 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
4026 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
4027 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
4028 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
4029 DRM_FORMAT_RGBX8888),
4030
4031 /* OMAP_DSS_VIDEO2 */
4032 COLOR_ARRAY(
4033 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
4034 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
4035 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
4036 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
4037 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
4038 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
4039 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
4040 DRM_FORMAT_RGBX8888),
4041
4042 /* OMAP_DSS_VIDEO3 */
4043 COLOR_ARRAY(
4044 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
4045 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
4046 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
4047 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
4048 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
4049 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
4050 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
4051 DRM_FORMAT_RGBX8888),
4052
4053 /* OMAP_DSS_WB */
4054 COLOR_ARRAY(
4055 DRM_FORMAT_RGB565, DRM_FORMAT_RGBX4444,
4056 DRM_FORMAT_YUYV, DRM_FORMAT_ARGB1555,
4057 DRM_FORMAT_RGBA8888, DRM_FORMAT_NV12,
4058 DRM_FORMAT_RGBA4444, DRM_FORMAT_XRGB8888,
4059 DRM_FORMAT_RGB888, DRM_FORMAT_UYVY,
4060 DRM_FORMAT_ARGB4444, DRM_FORMAT_XRGB1555,
4061 DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB4444,
4062 DRM_FORMAT_RGBX8888),
4063};
4064
Tomi Valkeinenede92692015-06-04 14:12:16 +03004065static const struct dispc_features omap24xx_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304066 .sw_start = 5,
4067 .fp_start = 15,
4068 .bp_start = 27,
4069 .sw_max = 64,
4070 .vp_max = 255,
4071 .hp_max = 256,
Archit Taneja33b89922012-11-14 13:50:15 +05304072 .mgr_width_start = 10,
4073 .mgr_height_start = 26,
4074 .mgr_width_max = 2048,
4075 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304076 .max_lcd_pclk = 66500000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004077 .max_downscale = 2,
4078 /*
4079 * Assume the line width buffer to be 768 pixels as OMAP2 DISPC scaler
4080 * cannot scale an image width larger than 768.
4081 */
4082 .max_line_width = 768,
4083 .min_pcd = 2,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304084 .calc_scaling = dispc_ovl_calc_scaling_24xx,
4085 .calc_core_clk = calc_core_clk_24xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03004086 .num_fifos = 3,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004087 .features = omap2_dispc_features_list,
4088 .num_features = ARRAY_SIZE(omap2_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004089 .reg_fields = omap2_dispc_reg_fields,
4090 .num_reg_fields = ARRAY_SIZE(omap2_dispc_reg_fields),
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004091 .overlay_caps = omap2_dispc_overlay_caps,
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03004092 .supported_color_modes = omap2_dispc_supported_color_modes,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004093 .num_mgrs = 2,
4094 .num_ovls = 3,
Laurent Pinchart28550472017-08-05 01:44:03 +03004095 .buffer_size_unit = 1,
4096 .burst_size_unit = 8,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02004097 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304098 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03004099 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304100};
4101
Tomi Valkeinenede92692015-06-04 14:12:16 +03004102static const struct dispc_features omap34xx_rev1_0_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304103 .sw_start = 5,
4104 .fp_start = 15,
4105 .bp_start = 27,
4106 .sw_max = 64,
4107 .vp_max = 255,
4108 .hp_max = 256,
Archit Taneja33b89922012-11-14 13:50:15 +05304109 .mgr_width_start = 10,
4110 .mgr_height_start = 26,
4111 .mgr_width_max = 2048,
4112 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304113 .max_lcd_pclk = 173000000,
4114 .max_tv_pclk = 59000000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004115 .max_downscale = 4,
4116 .max_line_width = 1024,
4117 .min_pcd = 1,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304118 .calc_scaling = dispc_ovl_calc_scaling_34xx,
4119 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03004120 .num_fifos = 3,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004121 .features = omap3_dispc_features_list,
4122 .num_features = ARRAY_SIZE(omap3_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004123 .reg_fields = omap3_dispc_reg_fields,
4124 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields),
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004125 .overlay_caps = omap3430_dispc_overlay_caps,
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03004126 .supported_color_modes = omap3_dispc_supported_color_modes,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004127 .num_mgrs = 2,
4128 .num_ovls = 3,
Laurent Pinchart28550472017-08-05 01:44:03 +03004129 .buffer_size_unit = 1,
4130 .burst_size_unit = 8,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02004131 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304132 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03004133 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304134};
4135
Tomi Valkeinenede92692015-06-04 14:12:16 +03004136static const struct dispc_features omap34xx_rev3_0_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304137 .sw_start = 7,
4138 .fp_start = 19,
4139 .bp_start = 31,
4140 .sw_max = 256,
4141 .vp_max = 4095,
4142 .hp_max = 4096,
Archit Taneja33b89922012-11-14 13:50:15 +05304143 .mgr_width_start = 10,
4144 .mgr_height_start = 26,
4145 .mgr_width_max = 2048,
4146 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304147 .max_lcd_pclk = 173000000,
4148 .max_tv_pclk = 59000000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004149 .max_downscale = 4,
4150 .max_line_width = 1024,
4151 .min_pcd = 1,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304152 .calc_scaling = dispc_ovl_calc_scaling_34xx,
4153 .calc_core_clk = calc_core_clk_34xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03004154 .num_fifos = 3,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004155 .features = omap3_dispc_features_list,
4156 .num_features = ARRAY_SIZE(omap3_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004157 .reg_fields = omap3_dispc_reg_fields,
4158 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields),
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004159 .overlay_caps = omap3430_dispc_overlay_caps,
4160 .supported_color_modes = omap3_dispc_supported_color_modes,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004161 .num_mgrs = 2,
4162 .num_ovls = 3,
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004163 .buffer_size_unit = 1,
4164 .burst_size_unit = 8,
4165 .no_framedone_tv = true,
4166 .set_max_preload = false,
4167 .last_pixel_inc_missing = true,
4168};
4169
4170static const struct dispc_features omap36xx_dispc_feats = {
4171 .sw_start = 7,
4172 .fp_start = 19,
4173 .bp_start = 31,
4174 .sw_max = 256,
4175 .vp_max = 4095,
4176 .hp_max = 4096,
4177 .mgr_width_start = 10,
4178 .mgr_height_start = 26,
4179 .mgr_width_max = 2048,
4180 .mgr_height_max = 2048,
4181 .max_lcd_pclk = 173000000,
4182 .max_tv_pclk = 59000000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004183 .max_downscale = 4,
4184 .max_line_width = 1024,
4185 .min_pcd = 1,
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004186 .calc_scaling = dispc_ovl_calc_scaling_34xx,
4187 .calc_core_clk = calc_core_clk_34xx,
4188 .num_fifos = 3,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004189 .features = omap3_dispc_features_list,
4190 .num_features = ARRAY_SIZE(omap3_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004191 .reg_fields = omap3_dispc_reg_fields,
4192 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields),
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004193 .overlay_caps = omap3630_dispc_overlay_caps,
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03004194 .supported_color_modes = omap3_dispc_supported_color_modes,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004195 .num_mgrs = 2,
4196 .num_ovls = 3,
4197 .buffer_size_unit = 1,
4198 .burst_size_unit = 8,
4199 .no_framedone_tv = true,
4200 .set_max_preload = false,
4201 .last_pixel_inc_missing = true,
4202};
4203
4204static const struct dispc_features am43xx_dispc_feats = {
4205 .sw_start = 7,
4206 .fp_start = 19,
4207 .bp_start = 31,
4208 .sw_max = 256,
4209 .vp_max = 4095,
4210 .hp_max = 4096,
4211 .mgr_width_start = 10,
4212 .mgr_height_start = 26,
4213 .mgr_width_max = 2048,
4214 .mgr_height_max = 2048,
4215 .max_lcd_pclk = 173000000,
4216 .max_tv_pclk = 59000000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004217 .max_downscale = 4,
4218 .max_line_width = 1024,
4219 .min_pcd = 1,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004220 .calc_scaling = dispc_ovl_calc_scaling_34xx,
4221 .calc_core_clk = calc_core_clk_34xx,
4222 .num_fifos = 3,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004223 .features = am43xx_dispc_features_list,
4224 .num_features = ARRAY_SIZE(am43xx_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004225 .reg_fields = omap3_dispc_reg_fields,
4226 .num_reg_fields = ARRAY_SIZE(omap3_dispc_reg_fields),
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004227 .overlay_caps = omap3430_dispc_overlay_caps,
4228 .supported_color_modes = omap3_dispc_supported_color_modes,
4229 .num_mgrs = 1,
4230 .num_ovls = 3,
Laurent Pinchart28550472017-08-05 01:44:03 +03004231 .buffer_size_unit = 1,
4232 .burst_size_unit = 8,
Tomi Valkeinencffa9472012-11-08 10:01:33 +02004233 .no_framedone_tv = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304234 .set_max_preload = false,
Tomi Valkeinenf2aee312015-04-10 12:48:34 +03004235 .last_pixel_inc_missing = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304236};
4237
Tomi Valkeinenede92692015-06-04 14:12:16 +03004238static const struct dispc_features omap44xx_dispc_feats = {
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304239 .sw_start = 7,
4240 .fp_start = 19,
4241 .bp_start = 31,
4242 .sw_max = 256,
4243 .vp_max = 4095,
4244 .hp_max = 4096,
Archit Taneja33b89922012-11-14 13:50:15 +05304245 .mgr_width_start = 10,
4246 .mgr_height_start = 26,
4247 .mgr_width_max = 2048,
4248 .mgr_height_max = 2048,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304249 .max_lcd_pclk = 170000000,
4250 .max_tv_pclk = 185625000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004251 .max_downscale = 4,
4252 .max_line_width = 2048,
4253 .min_pcd = 1,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304254 .calc_scaling = dispc_ovl_calc_scaling_44xx,
4255 .calc_core_clk = calc_core_clk_44xx,
Tomi Valkeinen42a69612012-08-22 16:56:57 +03004256 .num_fifos = 5,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004257 .features = omap4_dispc_features_list,
4258 .num_features = ARRAY_SIZE(omap4_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004259 .reg_fields = omap4_dispc_reg_fields,
4260 .num_reg_fields = ARRAY_SIZE(omap4_dispc_reg_fields),
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004261 .overlay_caps = omap4_dispc_overlay_caps,
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03004262 .supported_color_modes = omap4_dispc_supported_color_modes,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004263 .num_mgrs = 3,
4264 .num_ovls = 4,
Laurent Pinchart28550472017-08-05 01:44:03 +03004265 .buffer_size_unit = 16,
4266 .burst_size_unit = 16,
Tomi Valkeinen66a0f9e2012-08-22 16:57:02 +03004267 .gfx_fifo_workaround = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304268 .set_max_preload = true,
Tomi Valkeinene5f80912015-10-21 13:08:59 +03004269 .supports_sync_align = true,
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02004270 .has_writeback = true,
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02004271 .supports_double_pixel = true,
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02004272 .reverse_ilace_field_order = true,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004273 .has_gamma_table = true,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004274 .has_gamma_i734_bug = true,
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304275};
4276
Tomi Valkeinenede92692015-06-04 14:12:16 +03004277static const struct dispc_features omap54xx_dispc_feats = {
Archit Taneja264236f2012-11-14 13:50:16 +05304278 .sw_start = 7,
4279 .fp_start = 19,
4280 .bp_start = 31,
4281 .sw_max = 256,
4282 .vp_max = 4095,
4283 .hp_max = 4096,
4284 .mgr_width_start = 11,
4285 .mgr_height_start = 27,
4286 .mgr_width_max = 4096,
4287 .mgr_height_max = 4096,
Archit Tanejaca5ca692013-03-26 19:15:22 +05304288 .max_lcd_pclk = 170000000,
4289 .max_tv_pclk = 186000000,
Laurent Pinchartc4ff6ea2017-08-05 01:44:16 +03004290 .max_downscale = 4,
4291 .max_line_width = 2048,
4292 .min_pcd = 1,
Archit Taneja264236f2012-11-14 13:50:16 +05304293 .calc_scaling = dispc_ovl_calc_scaling_44xx,
4294 .calc_core_clk = calc_core_clk_44xx,
4295 .num_fifos = 5,
Laurent Pinchart1ac0c892017-08-05 01:44:14 +03004296 .features = omap5_dispc_features_list,
4297 .num_features = ARRAY_SIZE(omap5_dispc_features_list),
Laurent Pinchart38dc0702017-08-05 01:44:08 +03004298 .reg_fields = omap4_dispc_reg_fields,
4299 .num_reg_fields = ARRAY_SIZE(omap4_dispc_reg_fields),
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004300 .overlay_caps = omap4_dispc_overlay_caps,
Laurent Pinchart94f96ad2017-08-05 01:44:04 +03004301 .supported_color_modes = omap4_dispc_supported_color_modes,
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004302 .num_mgrs = 4,
4303 .num_ovls = 4,
Laurent Pinchart28550472017-08-05 01:44:03 +03004304 .buffer_size_unit = 16,
4305 .burst_size_unit = 16,
Archit Taneja264236f2012-11-14 13:50:16 +05304306 .gfx_fifo_workaround = true,
Archit Tanejad0df9a22013-03-26 19:15:25 +05304307 .mstandby_workaround = true,
Archit Taneja8bc65552013-12-17 16:40:21 +05304308 .set_max_preload = true,
Tomi Valkeinene5f80912015-10-21 13:08:59 +03004309 .supports_sync_align = true,
Tomi Valkeinen20efbc32015-11-04 17:10:44 +02004310 .has_writeback = true,
Tomi Valkeinen3a38ed532016-01-13 18:41:31 +02004311 .supports_double_pixel = true,
Tomi Valkeinenb7536d62016-01-13 18:41:36 +02004312 .reverse_ilace_field_order = true,
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004313 .has_gamma_table = true,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004314 .has_gamma_i734_bug = true,
Archit Taneja264236f2012-11-14 13:50:16 +05304315};
4316
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004317static irqreturn_t dispc_irq_handler(int irq, void *arg)
4318{
4319 if (!dispc.is_enabled)
4320 return IRQ_NONE;
4321
4322 return dispc.user_handler(irq, dispc.user_data);
4323}
4324
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004325static int dispc_request_irq(struct dispc_device *dispc, irq_handler_t handler,
4326 void *dev_id)
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004327{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004328 int r;
4329
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004330 if (dispc->user_handler != NULL)
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004331 return -EBUSY;
4332
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004333 dispc->user_handler = handler;
4334 dispc->user_data = dev_id;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004335
4336 /* ensure the dispc_irq_handler sees the values above */
4337 smp_wmb();
4338
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004339 r = devm_request_irq(&dispc->pdev->dev, dispc->irq, dispc_irq_handler,
4340 IRQF_SHARED, "OMAP DISPC", dispc);
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004341 if (r) {
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004342 dispc->user_handler = NULL;
4343 dispc->user_data = NULL;
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004344 }
4345
4346 return r;
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004347}
4348
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004349static void dispc_free_irq(struct dispc_device *dispc, void *dev_id)
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004350{
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004351 devm_free_irq(&dispc->pdev->dev, dispc->irq, dispc);
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004352
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004353 dispc->user_handler = NULL;
4354 dispc->user_data = NULL;
Tomi Valkeinen96e2e632012-10-10 15:55:19 +03004355}
4356
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004357static u32 dispc_get_memory_bandwidth_limit(struct dispc_device *dispc)
Peter Ujfalusi867d7e02017-11-30 14:12:36 +02004358{
4359 u32 limit = 0;
4360
4361 /* Optional maximum memory bandwidth */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004362 of_property_read_u32(dispc->pdev->dev.of_node, "max-memory-bandwidth",
Peter Ujfalusi867d7e02017-11-30 14:12:36 +02004363 &limit);
4364
4365 return limit;
4366}
4367
Jyri Sarhafbff0102016-06-07 15:09:16 +03004368/*
4369 * Workaround for errata i734 in DSS dispc
4370 * - LCD1 Gamma Correction Is Not Working When GFX Pipe Is Disabled
4371 *
4372 * For gamma tables to work on LCD1 the GFX plane has to be used at
4373 * least once after DSS HW has come out of reset. The workaround
4374 * sets up a minimal LCD setup with GFX plane and waits for one
4375 * vertical sync irq before disabling the setup and continuing with
4376 * the context restore. The physical outputs are gated during the
4377 * operation. This workaround requires that gamma table's LOADMODE
4378 * is set to 0x2 in DISPC_CONTROL1 register.
4379 *
4380 * For details see:
4381 * OMAP543x Multimedia Device Silicon Revision 2.0 Silicon Errata
4382 * Literature Number: SWPZ037E
4383 * Or some other relevant errata document for the DSS IP version.
4384 */
4385
4386static const struct dispc_errata_i734_data {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004387 struct videomode vm;
Jyri Sarhafbff0102016-06-07 15:09:16 +03004388 struct omap_overlay_info ovli;
4389 struct omap_overlay_manager_info mgri;
4390 struct dss_lcd_mgr_config lcd_conf;
4391} i734 = {
Peter Ujfalusida11bbbb2016-09-22 14:07:04 +03004392 .vm = {
Peter Ujfalusifb7f3c42016-09-22 14:06:47 +03004393 .hactive = 8, .vactive = 1,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004394 .pixelclock = 16000000,
Peter Ujfalusia85f4a82016-09-22 14:06:50 +03004395 .hsync_len = 8, .hfront_porch = 4, .hback_porch = 4,
Peter Ujfalusi458540c2016-09-22 14:06:53 +03004396 .vsync_len = 1, .vfront_porch = 1, .vback_porch = 1,
Peter Ujfalusi6b44cd22016-09-22 14:06:57 +03004397
Peter Ujfalusi3fa3ab42016-09-22 14:06:58 +03004398 .flags = DISPLAY_FLAGS_HSYNC_LOW | DISPLAY_FLAGS_VSYNC_LOW |
Peter Ujfalusid34afb72016-09-22 14:07:01 +03004399 DISPLAY_FLAGS_DE_HIGH | DISPLAY_FLAGS_SYNC_POSEDGE |
4400 DISPLAY_FLAGS_PIXDATA_POSEDGE,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004401 },
4402 .ovli = {
4403 .screen_width = 1,
4404 .width = 1, .height = 1,
Tomi Valkeinen41aff422017-05-04 11:31:56 +03004405 .fourcc = DRM_FORMAT_XRGB8888,
Tomi Valkeinen0bd97c42017-05-16 11:05:09 +03004406 .rotation = DRM_MODE_ROTATE_0,
Tomi Valkeinen517a8a952017-05-03 14:14:27 +03004407 .rotation_type = OMAP_DSS_ROT_NONE,
Jyri Sarhafbff0102016-06-07 15:09:16 +03004408 .pos_x = 0, .pos_y = 0,
4409 .out_width = 0, .out_height = 0,
4410 .global_alpha = 0xff,
4411 .pre_mult_alpha = 0,
4412 .zorder = 0,
4413 },
4414 .mgri = {
4415 .default_color = 0,
4416 .trans_enabled = false,
4417 .partial_alpha_enabled = false,
4418 .cpr_enable = false,
4419 },
4420 .lcd_conf = {
4421 .io_pad_mode = DSS_IO_PAD_MODE_BYPASS,
4422 .stallmode = false,
4423 .fifohandcheck = false,
4424 .clock_info = {
4425 .lck_div = 1,
4426 .pck_div = 2,
4427 },
4428 .video_port_width = 24,
4429 .lcden_sig_polarity = 0,
4430 },
4431};
4432
4433static struct i734_buf {
4434 size_t size;
4435 dma_addr_t paddr;
4436 void *vaddr;
4437} i734_buf;
4438
4439static int dispc_errata_i734_wa_init(void)
4440{
4441 if (!dispc.feat->has_gamma_i734_bug)
4442 return 0;
4443
4444 i734_buf.size = i734.ovli.width * i734.ovli.height *
Tomi Valkeinen41aff422017-05-04 11:31:56 +03004445 color_mode_to_bpp(i734.ovli.fourcc) / 8;
Jyri Sarhafbff0102016-06-07 15:09:16 +03004446
4447 i734_buf.vaddr = dma_alloc_writecombine(&dispc.pdev->dev, i734_buf.size,
4448 &i734_buf.paddr, GFP_KERNEL);
4449 if (!i734_buf.vaddr) {
4450 dev_err(&dispc.pdev->dev, "%s: dma_alloc_writecombine failed",
4451 __func__);
4452 return -ENOMEM;
4453 }
4454
4455 return 0;
4456}
4457
4458static void dispc_errata_i734_wa_fini(void)
4459{
4460 if (!dispc.feat->has_gamma_i734_bug)
4461 return;
4462
4463 dma_free_writecombine(&dispc.pdev->dev, i734_buf.size, i734_buf.vaddr,
4464 i734_buf.paddr);
4465}
4466
4467static void dispc_errata_i734_wa(void)
4468{
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004469 u32 framedone_irq = dispc_mgr_get_framedone_irq(&dispc,
4470 OMAP_DSS_CHANNEL_LCD);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004471 struct omap_overlay_info ovli;
4472 struct dss_lcd_mgr_config lcd_conf;
4473 u32 gatestate;
4474 unsigned int count;
4475
4476 if (!dispc.feat->has_gamma_i734_bug)
4477 return;
4478
4479 gatestate = REG_GET(DISPC_CONFIG, 8, 4);
4480
4481 ovli = i734.ovli;
4482 ovli.paddr = i734_buf.paddr;
4483 lcd_conf = i734.lcd_conf;
4484
4485 /* Gate all LCD1 outputs */
4486 REG_FLD_MOD(DISPC_CONFIG, 0x1f, 8, 4);
4487
4488 /* Setup and enable GFX plane */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004489 dispc_ovl_setup(&dispc, OMAP_DSS_GFX, &ovli, &i734.vm, false,
4490 OMAP_DSS_CHANNEL_LCD);
4491 dispc_ovl_enable(&dispc, OMAP_DSS_GFX, true);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004492
4493 /* Set up and enable display manager for LCD1 */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004494 dispc_mgr_setup(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.mgri);
Laurent Pinchart8a7eda72018-02-13 14:00:43 +02004495 dispc_calc_clock_rates(&dispc, dss_get_dispc_clk_rate(dispc.dss),
Jyri Sarhafbff0102016-06-07 15:09:16 +03004496 &lcd_conf.clock_info);
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004497 dispc_mgr_set_lcd_config(&dispc, OMAP_DSS_CHANNEL_LCD, &lcd_conf);
4498 dispc_mgr_set_timings(&dispc, OMAP_DSS_CHANNEL_LCD, &i734.vm);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004499
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004500 dispc_clear_irqstatus(&dispc, framedone_irq);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004501
4502 /* Enable and shut the channel to produce just one frame */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004503 dispc_mgr_enable(&dispc, OMAP_DSS_CHANNEL_LCD, true);
4504 dispc_mgr_enable(&dispc, OMAP_DSS_CHANNEL_LCD, false);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004505
4506 /* Busy wait for framedone. We can't fiddle with irq handlers
4507 * in PM resume. Typically the loop runs less than 5 times and
4508 * waits less than a micro second.
4509 */
4510 count = 0;
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004511 while (!(dispc_read_irqstatus(&dispc) & framedone_irq)) {
Jyri Sarhafbff0102016-06-07 15:09:16 +03004512 if (count++ > 10000) {
4513 dev_err(&dispc.pdev->dev, "%s: framedone timeout\n",
4514 __func__);
4515 break;
4516 }
4517 }
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004518 dispc_ovl_enable(&dispc, OMAP_DSS_GFX, false);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004519
4520 /* Clear all irq bits before continuing */
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004521 dispc_clear_irqstatus(&dispc, 0xffffffff);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004522
4523 /* Restore the original state to LCD1 output gates */
4524 REG_FLD_MOD(DISPC_CONFIG, gatestate, 8, 4);
4525}
4526
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004527static const struct dispc_ops dispc_ops = {
4528 .read_irqstatus = dispc_read_irqstatus,
4529 .clear_irqstatus = dispc_clear_irqstatus,
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004530 .write_irqenable = dispc_write_irqenable,
4531
4532 .request_irq = dispc_request_irq,
4533 .free_irq = dispc_free_irq,
4534
4535 .runtime_get = dispc_runtime_get,
4536 .runtime_put = dispc_runtime_put,
4537
4538 .get_num_ovls = dispc_get_num_ovls,
4539 .get_num_mgrs = dispc_get_num_mgrs,
4540
Peter Ujfalusi867d7e02017-11-30 14:12:36 +02004541 .get_memory_bandwidth_limit = dispc_get_memory_bandwidth_limit,
4542
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004543 .mgr_enable = dispc_mgr_enable,
4544 .mgr_is_enabled = dispc_mgr_is_enabled,
4545 .mgr_get_vsync_irq = dispc_mgr_get_vsync_irq,
4546 .mgr_get_framedone_irq = dispc_mgr_get_framedone_irq,
4547 .mgr_get_sync_lost_irq = dispc_mgr_get_sync_lost_irq,
4548 .mgr_go_busy = dispc_mgr_go_busy,
4549 .mgr_go = dispc_mgr_go,
4550 .mgr_set_lcd_config = dispc_mgr_set_lcd_config,
4551 .mgr_set_timings = dispc_mgr_set_timings,
4552 .mgr_setup = dispc_mgr_setup,
4553 .mgr_get_supported_outputs = dispc_mgr_get_supported_outputs,
4554 .mgr_gamma_size = dispc_mgr_gamma_size,
4555 .mgr_set_gamma = dispc_mgr_set_gamma,
4556
4557 .ovl_enable = dispc_ovl_enable,
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004558 .ovl_setup = dispc_ovl_setup,
4559 .ovl_get_color_modes = dispc_ovl_get_color_modes,
4560};
4561
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004562/* DISPC HW IP initialisation */
Laurent Pinchart7a143a42017-08-05 01:43:55 +03004563static const struct of_device_id dispc_of_match[] = {
4564 { .compatible = "ti,omap2-dispc", .data = &omap24xx_dispc_feats },
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004565 { .compatible = "ti,omap3-dispc", .data = &omap36xx_dispc_feats },
Laurent Pinchart7a143a42017-08-05 01:43:55 +03004566 { .compatible = "ti,omap4-dispc", .data = &omap44xx_dispc_feats },
4567 { .compatible = "ti,omap5-dispc", .data = &omap54xx_dispc_feats },
4568 { .compatible = "ti,dra7-dispc", .data = &omap54xx_dispc_feats },
4569 {},
4570};
4571
4572static const struct soc_device_attribute dispc_soc_devices[] = {
4573 { .machine = "OMAP3[45]*",
4574 .revision = "ES[12].?", .data = &omap34xx_rev1_0_dispc_feats },
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004575 { .machine = "OMAP3[45]*", .data = &omap34xx_rev3_0_dispc_feats },
4576 { .machine = "AM35*", .data = &omap34xx_rev3_0_dispc_feats },
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004577 { .machine = "AM43*", .data = &am43xx_dispc_feats },
Laurent Pinchart7a143a42017-08-05 01:43:55 +03004578 { /* sentinel */ }
4579};
4580
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004581static int dispc_bind(struct device *dev, struct device *master, void *data)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004582{
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004583 struct platform_device *pdev = to_platform_device(dev);
Laurent Pinchart7a143a42017-08-05 01:43:55 +03004584 const struct soc_device_attribute *soc;
Laurent Pinchart3cc62aa2018-02-13 14:00:25 +02004585 struct dss_device *dss = dss_get_device(master);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004586 u32 rev;
archit tanejaaffe3602011-02-23 08:41:03 +00004587 int r = 0;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004588 struct resource *dispc_mem;
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00004589 struct device_node *np = pdev->dev.of_node;
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004590
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004591 dispc.pdev = pdev;
Laurent Pinchart3cc62aa2018-02-13 14:00:25 +02004592 dispc.dss = dss;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004593
Tomi Valkeinend49cd152014-11-10 12:23:00 +02004594 spin_lock_init(&dispc.control_lock);
4595
Laurent Pinchart7a143a42017-08-05 01:43:55 +03004596 /*
Laurent Pinchartacf591c2017-08-05 01:44:06 +03004597 * The OMAP3-based models can't be told apart using the compatible
Laurent Pinchartfcd41882017-08-05 01:44:05 +03004598 * string, use SoC device matching.
Laurent Pinchart7a143a42017-08-05 01:43:55 +03004599 */
4600 soc = soc_device_match(dispc_soc_devices);
4601 if (soc)
4602 dispc.feat = soc->data;
4603 else
4604 dispc.feat = of_match_device(dispc_of_match, &pdev->dev)->data;
Chandrabhanu Mahapatradcbe7652012-07-03 12:26:51 +05304605
Jyri Sarhafbff0102016-06-07 15:09:16 +03004606 r = dispc_errata_i734_wa_init();
4607 if (r)
4608 return r;
4609
Senthilvadivu Guruswamyea9da362011-01-24 06:22:04 +00004610 dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0);
Laurent Pinchartb22622f2017-05-07 00:29:09 +03004611 dispc.base = devm_ioremap_resource(&pdev->dev, dispc_mem);
4612 if (IS_ERR(dispc.base))
4613 return PTR_ERR(dispc.base);
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004614
archit tanejaaffe3602011-02-23 08:41:03 +00004615 dispc.irq = platform_get_irq(dispc.pdev, 0);
4616 if (dispc.irq < 0) {
4617 DSSERR("platform_get_irq failed\n");
Tomi Valkeinencd3b3442012-01-25 13:31:04 +02004618 return -ENODEV;
archit tanejaaffe3602011-02-23 08:41:03 +00004619 }
4620
Tomi Valkeinen0006fd62014-09-05 19:15:03 +00004621 if (np && of_property_read_bool(np, "syscon-pol")) {
4622 dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
4623 if (IS_ERR(dispc.syscon_pol)) {
4624 dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
4625 return PTR_ERR(dispc.syscon_pol);
4626 }
4627
4628 if (of_property_read_u32_index(np, "syscon-pol", 1,
4629 &dispc.syscon_pol_offset)) {
4630 dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
4631 return -EINVAL;
4632 }
4633 }
4634
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004635 r = dispc_init_gamma_tables();
4636 if (r)
4637 return r;
4638
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004639 pm_runtime_enable(&pdev->dev);
4640
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004641 r = dispc_runtime_get(&dispc);
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004642 if (r)
4643 goto err_runtime_get;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004644
4645 _omap_dispc_initial_config();
4646
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004647 rev = dispc_read_reg(DISPC_REVISION);
Sumit Semwala06b62f2011-01-24 06:22:03 +00004648 dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n",
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004649 FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
4650
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004651 dispc_runtime_put(&dispc);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004652
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004653 dss->dispc = &dispc;
Laurent Pinchartd3541ca2018-02-13 14:00:41 +02004654 dss->dispc_ops = &dispc_ops;
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004655
Laurent Pinchart1c4b92e2018-02-13 14:00:31 +02004656 dispc.debugfs = dss_debugfs_create_file(dss, "dispc", dispc_dump_regs,
Laurent Pinchartf33656e2018-02-13 14:00:29 +02004657 &dispc);
Tomi Valkeinene40402c2012-03-02 18:01:07 +02004658
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004659 return 0;
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004660
4661err_runtime_get:
4662 pm_runtime_disable(&pdev->dev);
archit tanejaaffe3602011-02-23 08:41:03 +00004663 return r;
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004664}
4665
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004666static void dispc_unbind(struct device *dev, struct device *master, void *data)
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004667{
Laurent Pinchartd3541ca2018-02-13 14:00:41 +02004668 struct dss_device *dss = dispc.dss;
4669
Laurent Pinchartf33656e2018-02-13 14:00:29 +02004670 dss_debugfs_remove_file(dispc.debugfs);
4671
Laurent Pinchart50638ae2018-02-13 14:00:42 +02004672 dss->dispc = NULL;
Laurent Pinchartd3541ca2018-02-13 14:00:41 +02004673 dss->dispc_ops = NULL;
Tomi Valkeinena1a376472015-11-05 19:44:38 +02004674
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004675 pm_runtime_disable(dev);
Jyri Sarhafbff0102016-06-07 15:09:16 +03004676
4677 dispc_errata_i734_wa_fini();
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004678}
Tomi Valkeinen04b1fc02013-05-14 10:55:19 +03004679
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004680static const struct component_ops dispc_component_ops = {
4681 .bind = dispc_bind,
4682 .unbind = dispc_unbind,
4683};
4684
4685static int dispc_probe(struct platform_device *pdev)
4686{
4687 return component_add(&pdev->dev, &dispc_component_ops);
4688}
4689
4690static int dispc_remove(struct platform_device *pdev)
4691{
4692 component_del(&pdev->dev, &dispc_component_ops);
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004693 return 0;
4694}
4695
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004696static int dispc_runtime_suspend(struct device *dev)
4697{
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004698 dispc.is_enabled = false;
4699 /* ensure the dispc_irq_handler sees the is_enabled value */
4700 smp_wmb();
4701 /* wait for current handler to finish before turning the DISPC off */
4702 synchronize_irq(dispc.irq);
4703
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004704 dispc_save_context();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004705
4706 return 0;
4707}
4708
4709static int dispc_runtime_resume(struct device *dev)
4710{
Tomi Valkeinen9229b512014-02-14 09:37:09 +02004711 /*
4712 * The reset value for load mode is 0 (OMAP_DSS_LOAD_CLUT_AND_FRAME)
4713 * but we always initialize it to 2 (OMAP_DSS_LOAD_FRAME_ONLY) in
4714 * _omap_dispc_initial_config(). We can thus use it to detect if
4715 * we have lost register context.
4716 */
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004717 if (REG_GET(DISPC_CONFIG, 2, 1) != OMAP_DSS_LOAD_FRAME_ONLY) {
4718 _omap_dispc_initial_config();
Tomi Valkeinen9229b512014-02-14 09:37:09 +02004719
Jyri Sarhafbff0102016-06-07 15:09:16 +03004720 dispc_errata_i734_wa();
4721
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004722 dispc_restore_context();
Jyri Sarhaacc3a232016-06-07 15:09:15 +03004723
4724 dispc_restore_gamma_tables();
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004725 }
Tomi Valkeinenbe07dcd72013-11-21 16:01:40 +02004726
Tomi Valkeinen0925afc2014-04-11 13:49:55 +03004727 dispc.is_enabled = true;
4728 /* ensure the dispc_irq_handler sees the is_enabled value */
4729 smp_wmb();
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004730
4731 return 0;
4732}
4733
4734static const struct dev_pm_ops dispc_pm_ops = {
4735 .runtime_suspend = dispc_runtime_suspend,
4736 .runtime_resume = dispc_runtime_resume,
4737};
4738
Andrew F. Davisd66c36a2017-12-05 14:29:32 -06004739struct platform_driver omap_dispchw_driver = {
Tomi Valkeinen736e60d2015-06-04 15:22:23 +03004740 .probe = dispc_probe,
4741 .remove = dispc_remove,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004742 .driver = {
4743 .name = "omapdss_dispc",
Tomi Valkeinen4fbafaf2011-05-27 10:52:19 +03004744 .pm = &dispc_pm_ops,
Tomi Valkeinend7977f82013-12-17 11:54:02 +02004745 .of_match_table = dispc_of_match,
Tomi Valkeinen422ccbd2014-10-16 09:54:25 +03004746 .suppress_bind_attrs = true,
Senthilvadivu Guruswamy060b6d92011-01-24 06:22:00 +00004747 },
4748};