1 /* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Author: Fabien Dessenne <fabien.dessenne@st.com> for STMicroelectronics. 4 * License terms: GNU General Public License (GPL), version 2 5 */ 6 7 #include <drm/drmP.h> 8 9 #include "sti_plane.h" 10 #include "sti_vid.h" 11 #include "sti_vtg.h" 12 13 /* Registers */ 14 #define VID_CTL 0x00 15 #define VID_ALP 0x04 16 #define VID_CLF 0x08 17 #define VID_VPO 0x0C 18 #define VID_VPS 0x10 19 #define VID_KEY1 0x28 20 #define VID_KEY2 0x2C 21 #define VID_MPR0 0x30 22 #define VID_MPR1 0x34 23 #define VID_MPR2 0x38 24 #define VID_MPR3 0x3C 25 #define VID_MST 0x68 26 #define VID_BC 0x70 27 #define VID_TINT 0x74 28 #define VID_CSAT 0x78 29 30 /* Registers values */ 31 #define VID_CTL_IGNORE (BIT(31) | BIT(30)) 32 #define VID_CTL_PSI_ENABLE (BIT(2) | BIT(1) | BIT(0)) 33 #define VID_ALP_OPAQUE 0x00000080 34 #define VID_BC_DFLT 0x00008000 35 #define VID_TINT_DFLT 0x00000000 36 #define VID_CSAT_DFLT 0x00000080 37 /* YCbCr to RGB BT709: 38 * R = Y+1.5391Cr 39 * G = Y-0.4590Cr-0.1826Cb 40 * B = Y+1.8125Cb */ 41 #define VID_MPR0_BT709 0x0A800000 42 #define VID_MPR1_BT709 0x0AC50000 43 #define VID_MPR2_BT709 0x07150545 44 #define VID_MPR3_BT709 0x00000AE8 45 /* YCbCr to RGB BT709: 46 * R = Y+1.3711Cr 47 * G = Y-0.6992Cr-0.3359Cb 48 * B = Y+1.7344Cb 49 */ 50 #define VID_MPR0_BT601 0x0A800000 51 #define VID_MPR1_BT601 0x0AAF0000 52 #define VID_MPR2_BT601 0x094E0754 53 #define VID_MPR3_BT601 0x00000ADD 54 55 #define VID_MIN_HD_HEIGHT 720 56 57 #define DBGFS_DUMP(reg) seq_printf(s, "\n %-25s 0x%08X", #reg, \ 58 readl(vid->regs + reg)) 59 60 static void vid_dbg_ctl(struct seq_file *s, int val) 61 { 62 val = val >> 30; 63 seq_puts(s, "\t"); 64 65 if (!(val & 1)) 66 seq_puts(s, "NOT "); 67 seq_puts(s, "ignored on main mixer - "); 68 69 if (!(val & 2)) 70 seq_puts(s, "NOT "); 71 seq_puts(s, "ignored on aux mixer"); 72 } 73 74 static void vid_dbg_vpo(struct seq_file *s, int val) 75 { 76 seq_printf(s, "\txdo:%4d\tydo:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF); 77 } 78 79 static void vid_dbg_vps(struct seq_file *s, int val) 80 { 81 seq_printf(s, "\txds:%4d\tyds:%4d", val & 0x0FFF, (val >> 16) & 0x0FFF); 82 } 83 84 static void vid_dbg_mst(struct seq_file *s, int val) 85 { 86 if (val & 1) 87 seq_puts(s, "\tBUFFER UNDERFLOW!"); 88 } 89 90 static int vid_dbg_show(struct seq_file *s, void *arg) 91 { 92 struct drm_info_node *node = s->private; 93 struct sti_vid *vid = (struct sti_vid *)node->info_ent->data; 94 struct drm_device *dev = node->minor->dev; 95 int ret; 96 97 ret = mutex_lock_interruptible(&dev->struct_mutex); 98 if (ret) 99 return ret; 100 101 seq_printf(s, "VID: (vaddr= 0x%p)", vid->regs); 102 103 DBGFS_DUMP(VID_CTL); 104 vid_dbg_ctl(s, readl(vid->regs + VID_CTL)); 105 DBGFS_DUMP(VID_ALP); 106 DBGFS_DUMP(VID_CLF); 107 DBGFS_DUMP(VID_VPO); 108 vid_dbg_vpo(s, readl(vid->regs + VID_VPO)); 109 DBGFS_DUMP(VID_VPS); 110 vid_dbg_vps(s, readl(vid->regs + VID_VPS)); 111 DBGFS_DUMP(VID_KEY1); 112 DBGFS_DUMP(VID_KEY2); 113 DBGFS_DUMP(VID_MPR0); 114 DBGFS_DUMP(VID_MPR1); 115 DBGFS_DUMP(VID_MPR2); 116 DBGFS_DUMP(VID_MPR3); 117 DBGFS_DUMP(VID_MST); 118 vid_dbg_mst(s, readl(vid->regs + VID_MST)); 119 DBGFS_DUMP(VID_BC); 120 DBGFS_DUMP(VID_TINT); 121 DBGFS_DUMP(VID_CSAT); 122 seq_puts(s, "\n"); 123 124 mutex_unlock(&dev->struct_mutex); 125 return 0; 126 } 127 128 static struct drm_info_list vid_debugfs_files[] = { 129 { "vid", vid_dbg_show, 0, NULL }, 130 }; 131 132 static int vid_debugfs_init(struct sti_vid *vid, struct drm_minor *minor) 133 { 134 unsigned int i; 135 136 for (i = 0; i < ARRAY_SIZE(vid_debugfs_files); i++) 137 vid_debugfs_files[i].data = vid; 138 139 return drm_debugfs_create_files(vid_debugfs_files, 140 ARRAY_SIZE(vid_debugfs_files), 141 minor->debugfs_root, minor); 142 } 143 144 void sti_vid_commit(struct sti_vid *vid, 145 struct drm_plane_state *state) 146 { 147 struct drm_crtc *crtc = state->crtc; 148 struct drm_display_mode *mode = &crtc->mode; 149 int dst_x = state->crtc_x; 150 int dst_y = state->crtc_y; 151 int dst_w = clamp_val(state->crtc_w, 0, mode->crtc_hdisplay - dst_x); 152 int dst_h = clamp_val(state->crtc_h, 0, mode->crtc_vdisplay - dst_y); 153 int src_h = state->src_h >> 16; 154 u32 val, ydo, xdo, yds, xds; 155 156 /* Input / output size 157 * Align to upper even value */ 158 dst_w = ALIGN(dst_w, 2); 159 dst_h = ALIGN(dst_h, 2); 160 161 /* Unmask */ 162 val = readl(vid->regs + VID_CTL); 163 val &= ~VID_CTL_IGNORE; 164 writel(val, vid->regs + VID_CTL); 165 166 ydo = sti_vtg_get_line_number(*mode, dst_y); 167 yds = sti_vtg_get_line_number(*mode, dst_y + dst_h - 1); 168 xdo = sti_vtg_get_pixel_number(*mode, dst_x); 169 xds = sti_vtg_get_pixel_number(*mode, dst_x + dst_w - 1); 170 171 writel((ydo << 16) | xdo, vid->regs + VID_VPO); 172 writel((yds << 16) | xds, vid->regs + VID_VPS); 173 174 /* Color conversion parameters */ 175 if (src_h >= VID_MIN_HD_HEIGHT) { 176 writel(VID_MPR0_BT709, vid->regs + VID_MPR0); 177 writel(VID_MPR1_BT709, vid->regs + VID_MPR1); 178 writel(VID_MPR2_BT709, vid->regs + VID_MPR2); 179 writel(VID_MPR3_BT709, vid->regs + VID_MPR3); 180 } else { 181 writel(VID_MPR0_BT601, vid->regs + VID_MPR0); 182 writel(VID_MPR1_BT601, vid->regs + VID_MPR1); 183 writel(VID_MPR2_BT601, vid->regs + VID_MPR2); 184 writel(VID_MPR3_BT601, vid->regs + VID_MPR3); 185 } 186 } 187 188 void sti_vid_disable(struct sti_vid *vid) 189 { 190 u32 val; 191 192 /* Mask */ 193 val = readl(vid->regs + VID_CTL); 194 val |= VID_CTL_IGNORE; 195 writel(val, vid->regs + VID_CTL); 196 } 197 198 static void sti_vid_init(struct sti_vid *vid) 199 { 200 /* Enable PSI, Mask layer */ 201 writel(VID_CTL_PSI_ENABLE | VID_CTL_IGNORE, vid->regs + VID_CTL); 202 203 /* Opaque */ 204 writel(VID_ALP_OPAQUE, vid->regs + VID_ALP); 205 206 /* Brightness, contrast, tint, saturation */ 207 writel(VID_BC_DFLT, vid->regs + VID_BC); 208 writel(VID_TINT_DFLT, vid->regs + VID_TINT); 209 writel(VID_CSAT_DFLT, vid->regs + VID_CSAT); 210 } 211 212 struct sti_vid *sti_vid_create(struct device *dev, struct drm_device *drm_dev, 213 int id, void __iomem *baseaddr) 214 { 215 struct sti_vid *vid; 216 217 vid = devm_kzalloc(dev, sizeof(*vid), GFP_KERNEL); 218 if (!vid) { 219 DRM_ERROR("Failed to allocate memory for VID\n"); 220 return NULL; 221 } 222 223 vid->dev = dev; 224 vid->regs = baseaddr; 225 vid->id = id; 226 227 sti_vid_init(vid); 228 229 if (vid_debugfs_init(vid, drm_dev->primary)) 230 DRM_ERROR("VID debugfs setup failed\n"); 231 232 return vid; 233 } 234