1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright 2019 NXP. 4 */ 5 6 #include <linux/device.h> 7 #include <linux/slab.h> 8 9 #include "dcss-dev.h" 10 11 #define DCSS_SS_SYS_CTRL 0x00 12 #define RUN_EN BIT(0) 13 #define DCSS_SS_DISPLAY 0x10 14 #define LRC_X_POS 0 15 #define LRC_X_MASK GENMASK(12, 0) 16 #define LRC_Y_POS 16 17 #define LRC_Y_MASK GENMASK(28, 16) 18 #define DCSS_SS_HSYNC 0x20 19 #define DCSS_SS_VSYNC 0x30 20 #define SYNC_START_POS 0 21 #define SYNC_START_MASK GENMASK(12, 0) 22 #define SYNC_END_POS 16 23 #define SYNC_END_MASK GENMASK(28, 16) 24 #define SYNC_POL BIT(31) 25 #define DCSS_SS_DE_ULC 0x40 26 #define ULC_X_POS 0 27 #define ULC_X_MASK GENMASK(12, 0) 28 #define ULC_Y_POS 16 29 #define ULC_Y_MASK GENMASK(28, 16) 30 #define ULC_POL BIT(31) 31 #define DCSS_SS_DE_LRC 0x50 32 #define DCSS_SS_MODE 0x60 33 #define PIPE_MODE_POS 0 34 #define PIPE_MODE_MASK GENMASK(1, 0) 35 #define DCSS_SS_COEFF 0x70 36 #define HORIZ_A_POS 0 37 #define HORIZ_A_MASK GENMASK(3, 0) 38 #define HORIZ_B_POS 4 39 #define HORIZ_B_MASK GENMASK(7, 4) 40 #define HORIZ_C_POS 8 41 #define HORIZ_C_MASK GENMASK(11, 8) 42 #define HORIZ_H_NORM_POS 12 43 #define HORIZ_H_NORM_MASK GENMASK(14, 12) 44 #define VERT_A_POS 16 45 #define VERT_A_MASK GENMASK(19, 16) 46 #define VERT_B_POS 20 47 #define VERT_B_MASK GENMASK(23, 20) 48 #define VERT_C_POS 24 49 #define VERT_C_MASK GENMASK(27, 24) 50 #define VERT_H_NORM_POS 28 51 #define VERT_H_NORM_MASK GENMASK(30, 28) 52 #define DCSS_SS_CLIP_CB 0x80 53 #define DCSS_SS_CLIP_CR 0x90 54 #define CLIP_MIN_POS 0 55 #define CLIP_MIN_MASK GENMASK(9, 0) 56 #define CLIP_MAX_POS 0 57 #define CLIP_MAX_MASK GENMASK(23, 16) 58 #define DCSS_SS_INTER_MODE 0xA0 59 #define INT_EN BIT(0) 60 #define VSYNC_SHIFT BIT(1) 61 62 struct dcss_ss { 63 struct device *dev; 64 void __iomem *base_reg; 65 u32 base_ofs; 66 67 struct dcss_ctxld *ctxld; 68 u32 ctx_id; 69 70 bool in_use; 71 }; 72 73 static void dcss_ss_write(struct dcss_ss *ss, u32 val, u32 ofs) 74 { 75 if (!ss->in_use) 76 dcss_writel(val, ss->base_reg + ofs); 77 78 dcss_ctxld_write(ss->ctxld, ss->ctx_id, val, 79 ss->base_ofs + ofs); 80 } 81 82 int dcss_ss_init(struct dcss_dev *dcss, unsigned long ss_base) 83 { 84 struct dcss_ss *ss; 85 86 ss = kzalloc(sizeof(*ss), GFP_KERNEL); 87 if (!ss) 88 return -ENOMEM; 89 90 dcss->ss = ss; 91 ss->dev = dcss->dev; 92 ss->ctxld = dcss->ctxld; 93 94 ss->base_reg = ioremap(ss_base, SZ_4K); 95 if (!ss->base_reg) { 96 dev_err(dcss->dev, "ss: unable to remap ss base\n"); 97 kfree(ss); 98 return -ENOMEM; 99 } 100 101 ss->base_ofs = ss_base; 102 ss->ctx_id = CTX_SB_HP; 103 104 return 0; 105 } 106 107 void dcss_ss_exit(struct dcss_ss *ss) 108 { 109 /* stop SS */ 110 dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); 111 112 if (ss->base_reg) 113 iounmap(ss->base_reg); 114 115 kfree(ss); 116 } 117 118 void dcss_ss_subsam_set(struct dcss_ss *ss) 119 { 120 dcss_ss_write(ss, 0x41614161, DCSS_SS_COEFF); 121 dcss_ss_write(ss, 0, DCSS_SS_MODE); 122 dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CB); 123 dcss_ss_write(ss, 0x03ff0000, DCSS_SS_CLIP_CR); 124 } 125 126 void dcss_ss_sync_set(struct dcss_ss *ss, struct videomode *vm, 127 bool phsync, bool pvsync) 128 { 129 u16 lrc_x, lrc_y; 130 u16 hsync_start, hsync_end; 131 u16 vsync_start, vsync_end; 132 u16 de_ulc_x, de_ulc_y; 133 u16 de_lrc_x, de_lrc_y; 134 135 lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len + 136 vm->hactive - 1; 137 lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len + 138 vm->vactive - 1; 139 140 dcss_ss_write(ss, (lrc_y << LRC_Y_POS) | lrc_x, DCSS_SS_DISPLAY); 141 142 hsync_start = vm->hfront_porch + vm->hback_porch + vm->hsync_len + 143 vm->hactive - 1; 144 hsync_end = vm->hsync_len - 1; 145 146 dcss_ss_write(ss, (phsync ? SYNC_POL : 0) | 147 ((u32)hsync_end << SYNC_END_POS) | hsync_start, 148 DCSS_SS_HSYNC); 149 150 vsync_start = vm->vfront_porch - 1; 151 vsync_end = vm->vfront_porch + vm->vsync_len - 1; 152 153 dcss_ss_write(ss, (pvsync ? SYNC_POL : 0) | 154 ((u32)vsync_end << SYNC_END_POS) | vsync_start, 155 DCSS_SS_VSYNC); 156 157 de_ulc_x = vm->hsync_len + vm->hback_porch - 1; 158 de_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch; 159 160 dcss_ss_write(ss, SYNC_POL | ((u32)de_ulc_y << ULC_Y_POS) | de_ulc_x, 161 DCSS_SS_DE_ULC); 162 163 de_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1; 164 de_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch + 165 vm->vactive - 1; 166 167 dcss_ss_write(ss, (de_lrc_y << LRC_Y_POS) | de_lrc_x, DCSS_SS_DE_LRC); 168 } 169 170 void dcss_ss_enable(struct dcss_ss *ss) 171 { 172 dcss_ss_write(ss, RUN_EN, DCSS_SS_SYS_CTRL); 173 ss->in_use = true; 174 } 175 176 void dcss_ss_shutoff(struct dcss_ss *ss) 177 { 178 dcss_writel(0, ss->base_reg + DCSS_SS_SYS_CTRL); 179 ss->in_use = false; 180 } 181