1 /* 2 * Copyright (C) STMicroelectronics SA 2014 3 * Authors: Benjamin Gaignard <benjamin.gaignard@st.com> 4 * Fabien Dessenne <fabien.dessenne@st.com> 5 * Vincent Abriou <vincent.abriou@st.com> 6 * for STMicroelectronics. 7 * License terms: GNU General Public License (GPL), version 2 8 */ 9 10 #include <linux/module.h> 11 #include <linux/notifier.h> 12 #include <linux/platform_device.h> 13 14 #include <drm/drmP.h> 15 16 #include "sti_vtg.h" 17 18 #define VTG_TYPE_MASTER 0 19 #define VTG_TYPE_SLAVE_BY_EXT0 1 20 21 /* registers offset */ 22 #define VTG_MODE 0x0000 23 #define VTG_CLKLN 0x0008 24 #define VTG_HLFLN 0x000C 25 #define VTG_DRST_AUTOC 0x0010 26 #define VTG_VID_TFO 0x0040 27 #define VTG_VID_TFS 0x0044 28 #define VTG_VID_BFO 0x0048 29 #define VTG_VID_BFS 0x004C 30 31 #define VTG_HOST_ITS 0x0078 32 #define VTG_HOST_ITS_BCLR 0x007C 33 #define VTG_HOST_ITM_BCLR 0x0088 34 #define VTG_HOST_ITM_BSET 0x008C 35 36 #define VTG_H_HD_1 0x00C0 37 #define VTG_TOP_V_VD_1 0x00C4 38 #define VTG_BOT_V_VD_1 0x00C8 39 #define VTG_TOP_V_HD_1 0x00CC 40 #define VTG_BOT_V_HD_1 0x00D0 41 42 #define VTG_H_HD_2 0x00E0 43 #define VTG_TOP_V_VD_2 0x00E4 44 #define VTG_BOT_V_VD_2 0x00E8 45 #define VTG_TOP_V_HD_2 0x00EC 46 #define VTG_BOT_V_HD_2 0x00F0 47 48 #define VTG_H_HD_3 0x0100 49 #define VTG_TOP_V_VD_3 0x0104 50 #define VTG_BOT_V_VD_3 0x0108 51 #define VTG_TOP_V_HD_3 0x010C 52 #define VTG_BOT_V_HD_3 0x0110 53 54 #define VTG_H_HD_4 0x0120 55 #define VTG_TOP_V_VD_4 0x0124 56 #define VTG_BOT_V_VD_4 0x0128 57 #define VTG_TOP_V_HD_4 0x012c 58 #define VTG_BOT_V_HD_4 0x0130 59 60 #define VTG_IRQ_BOTTOM BIT(0) 61 #define VTG_IRQ_TOP BIT(1) 62 #define VTG_IRQ_MASK (VTG_IRQ_TOP | VTG_IRQ_BOTTOM) 63 64 /* Delay introduced by the HDMI in nb of pixel */ 65 #define HDMI_DELAY (5) 66 67 /* delay introduced by the Arbitrary Waveform Generator in nb of pixels */ 68 #define AWG_DELAY_HD (-9) 69 #define AWG_DELAY_ED (-8) 70 #define AWG_DELAY_SD (-7) 71 72 LIST_HEAD(vtg_lookup); 73 74 /** 75 * STI VTG structure 76 * 77 * @dev: pointer to device driver 78 * @data: data associated to the device 79 * @irq: VTG irq 80 * @type: VTG type (main or aux) 81 * @notifier_list: notifier callback 82 * @crtc: the CRTC for vblank event 83 * @slave: slave vtg 84 * @link: List node to link the structure in lookup list 85 */ 86 struct sti_vtg { 87 struct device *dev; 88 struct device_node *np; 89 void __iomem *regs; 90 int irq; 91 u32 irq_status; 92 struct raw_notifier_head notifier_list; 93 struct drm_crtc *crtc; 94 struct sti_vtg *slave; 95 struct list_head link; 96 }; 97 98 static void vtg_register(struct sti_vtg *vtg) 99 { 100 list_add_tail(&vtg->link, &vtg_lookup); 101 } 102 103 struct sti_vtg *of_vtg_find(struct device_node *np) 104 { 105 struct sti_vtg *vtg; 106 107 list_for_each_entry(vtg, &vtg_lookup, link) { 108 if (vtg->np == np) 109 return vtg; 110 } 111 return NULL; 112 } 113 114 static void vtg_reset(struct sti_vtg *vtg) 115 { 116 /* reset slave and then master */ 117 if (vtg->slave) 118 vtg_reset(vtg->slave); 119 120 writel(1, vtg->regs + VTG_DRST_AUTOC); 121 } 122 123 static void vtg_set_output_window(void __iomem *regs, 124 const struct drm_display_mode *mode) 125 { 126 u32 video_top_field_start; 127 u32 video_top_field_stop; 128 u32 video_bottom_field_start; 129 u32 video_bottom_field_stop; 130 u32 xstart = sti_vtg_get_pixel_number(*mode, 0); 131 u32 ystart = sti_vtg_get_line_number(*mode, 0); 132 u32 xstop = sti_vtg_get_pixel_number(*mode, mode->hdisplay - 1); 133 u32 ystop = sti_vtg_get_line_number(*mode, mode->vdisplay - 1); 134 135 /* Set output window to fit the display mode selected */ 136 video_top_field_start = (ystart << 16) | xstart; 137 video_top_field_stop = (ystop << 16) | xstop; 138 139 /* Only progressive supported for now */ 140 video_bottom_field_start = video_top_field_start; 141 video_bottom_field_stop = video_top_field_stop; 142 143 writel(video_top_field_start, regs + VTG_VID_TFO); 144 writel(video_top_field_stop, regs + VTG_VID_TFS); 145 writel(video_bottom_field_start, regs + VTG_VID_BFO); 146 writel(video_bottom_field_stop, regs + VTG_VID_BFS); 147 } 148 149 static void vtg_set_mode(struct sti_vtg *vtg, 150 int type, const struct drm_display_mode *mode) 151 { 152 u32 tmp; 153 154 if (vtg->slave) 155 vtg_set_mode(vtg->slave, VTG_TYPE_SLAVE_BY_EXT0, mode); 156 157 /* Set the number of clock cycles per line */ 158 writel(mode->htotal, vtg->regs + VTG_CLKLN); 159 160 /* Set Half Line Per Field (only progressive supported for now) */ 161 writel(mode->vtotal * 2, vtg->regs + VTG_HLFLN); 162 163 /* Program output window */ 164 vtg_set_output_window(vtg->regs, mode); 165 166 /* prepare VTG set 1 for HDMI */ 167 tmp = (mode->hsync_end - mode->hsync_start + HDMI_DELAY) << 16; 168 tmp |= HDMI_DELAY; 169 writel(tmp, vtg->regs + VTG_H_HD_1); 170 171 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 172 tmp |= 1; 173 writel(tmp, vtg->regs + VTG_TOP_V_VD_1); 174 writel(tmp, vtg->regs + VTG_BOT_V_VD_1); 175 176 tmp = HDMI_DELAY << 16; 177 tmp |= HDMI_DELAY; 178 writel(tmp, vtg->regs + VTG_TOP_V_HD_1); 179 writel(tmp, vtg->regs + VTG_BOT_V_HD_1); 180 181 /* prepare VTG set 2 for for HD DCS */ 182 tmp = (mode->hsync_end - mode->hsync_start) << 16; 183 writel(tmp, vtg->regs + VTG_H_HD_2); 184 185 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 186 tmp |= 1; 187 writel(tmp, vtg->regs + VTG_TOP_V_VD_2); 188 writel(tmp, vtg->regs + VTG_BOT_V_VD_2); 189 writel(0, vtg->regs + VTG_TOP_V_HD_2); 190 writel(0, vtg->regs + VTG_BOT_V_HD_2); 191 192 /* prepare VTG set 3 for HD Analog in HD mode */ 193 tmp = (mode->hsync_end - mode->hsync_start + AWG_DELAY_HD) << 16; 194 tmp |= mode->htotal + AWG_DELAY_HD; 195 writel(tmp, vtg->regs + VTG_H_HD_3); 196 197 tmp = (mode->vsync_end - mode->vsync_start) << 16; 198 tmp |= mode->vtotal; 199 writel(tmp, vtg->regs + VTG_TOP_V_VD_3); 200 writel(tmp, vtg->regs + VTG_BOT_V_VD_3); 201 202 tmp = (mode->htotal + AWG_DELAY_HD) << 16; 203 tmp |= mode->htotal + AWG_DELAY_HD; 204 writel(tmp, vtg->regs + VTG_TOP_V_HD_3); 205 writel(tmp, vtg->regs + VTG_BOT_V_HD_3); 206 207 /* Prepare VTG set 4 for DVO */ 208 tmp = (mode->hsync_end - mode->hsync_start) << 16; 209 writel(tmp, vtg->regs + VTG_H_HD_4); 210 211 tmp = (mode->vsync_end - mode->vsync_start + 1) << 16; 212 tmp |= 1; 213 writel(tmp, vtg->regs + VTG_TOP_V_VD_4); 214 writel(tmp, vtg->regs + VTG_BOT_V_VD_4); 215 writel(0, vtg->regs + VTG_TOP_V_HD_4); 216 writel(0, vtg->regs + VTG_BOT_V_HD_4); 217 218 /* mode */ 219 writel(type, vtg->regs + VTG_MODE); 220 } 221 222 static void vtg_enable_irq(struct sti_vtg *vtg) 223 { 224 /* clear interrupt status and mask */ 225 writel(0xFFFF, vtg->regs + VTG_HOST_ITS_BCLR); 226 writel(0xFFFF, vtg->regs + VTG_HOST_ITM_BCLR); 227 writel(VTG_IRQ_MASK, vtg->regs + VTG_HOST_ITM_BSET); 228 } 229 230 void sti_vtg_set_config(struct sti_vtg *vtg, 231 const struct drm_display_mode *mode) 232 { 233 /* write configuration */ 234 vtg_set_mode(vtg, VTG_TYPE_MASTER, mode); 235 236 vtg_reset(vtg); 237 238 /* enable irq for the vtg vblank synchro */ 239 if (vtg->slave) 240 vtg_enable_irq(vtg->slave); 241 else 242 vtg_enable_irq(vtg); 243 } 244 245 /** 246 * sti_vtg_get_line_number 247 * 248 * @mode: display mode to be used 249 * @y: line 250 * 251 * Return the line number according to the display mode taking 252 * into account the Sync and Back Porch information. 253 * Video frame line numbers start at 1, y starts at 0. 254 * In interlaced modes the start line is the field line number of the odd 255 * field, but y is still defined as a progressive frame. 256 */ 257 u32 sti_vtg_get_line_number(struct drm_display_mode mode, int y) 258 { 259 u32 start_line = mode.vtotal - mode.vsync_start + 1; 260 261 if (mode.flags & DRM_MODE_FLAG_INTERLACE) 262 start_line *= 2; 263 264 return start_line + y; 265 } 266 267 /** 268 * sti_vtg_get_pixel_number 269 * 270 * @mode: display mode to be used 271 * @x: row 272 * 273 * Return the pixel number according to the display mode taking 274 * into account the Sync and Back Porch information. 275 * Pixels are counted from 0. 276 */ 277 u32 sti_vtg_get_pixel_number(struct drm_display_mode mode, int x) 278 { 279 return mode.htotal - mode.hsync_start + x; 280 } 281 282 int sti_vtg_register_client(struct sti_vtg *vtg, struct notifier_block *nb, 283 struct drm_crtc *crtc) 284 { 285 if (vtg->slave) 286 return sti_vtg_register_client(vtg->slave, nb, crtc); 287 288 vtg->crtc = crtc; 289 return raw_notifier_chain_register(&vtg->notifier_list, nb); 290 } 291 292 int sti_vtg_unregister_client(struct sti_vtg *vtg, struct notifier_block *nb) 293 { 294 if (vtg->slave) 295 return sti_vtg_unregister_client(vtg->slave, nb); 296 297 return raw_notifier_chain_unregister(&vtg->notifier_list, nb); 298 } 299 300 static irqreturn_t vtg_irq_thread(int irq, void *arg) 301 { 302 struct sti_vtg *vtg = arg; 303 u32 event; 304 305 event = (vtg->irq_status & VTG_IRQ_TOP) ? 306 VTG_TOP_FIELD_EVENT : VTG_BOTTOM_FIELD_EVENT; 307 308 raw_notifier_call_chain(&vtg->notifier_list, event, vtg->crtc); 309 310 return IRQ_HANDLED; 311 } 312 313 static irqreturn_t vtg_irq(int irq, void *arg) 314 { 315 struct sti_vtg *vtg = arg; 316 317 vtg->irq_status = readl(vtg->regs + VTG_HOST_ITS); 318 319 writel(vtg->irq_status, vtg->regs + VTG_HOST_ITS_BCLR); 320 321 /* force sync bus write */ 322 readl(vtg->regs + VTG_HOST_ITS); 323 324 return IRQ_WAKE_THREAD; 325 } 326 327 static int vtg_probe(struct platform_device *pdev) 328 { 329 struct device *dev = &pdev->dev; 330 struct device_node *np; 331 struct sti_vtg *vtg; 332 struct resource *res; 333 int ret; 334 335 vtg = devm_kzalloc(dev, sizeof(*vtg), GFP_KERNEL); 336 if (!vtg) 337 return -ENOMEM; 338 339 vtg->dev = dev; 340 vtg->np = pdev->dev.of_node; 341 342 /* Get Memory ressources */ 343 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 344 if (!res) { 345 DRM_ERROR("Get memory resource failed\n"); 346 return -ENOMEM; 347 } 348 vtg->regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); 349 350 np = of_parse_phandle(pdev->dev.of_node, "st,slave", 0); 351 if (np) { 352 vtg->slave = of_vtg_find(np); 353 354 if (!vtg->slave) 355 return -EPROBE_DEFER; 356 } else { 357 vtg->irq = platform_get_irq(pdev, 0); 358 if (IS_ERR_VALUE(vtg->irq)) { 359 DRM_ERROR("Failed to get VTG interrupt\n"); 360 return vtg->irq; 361 } 362 363 RAW_INIT_NOTIFIER_HEAD(&vtg->notifier_list); 364 365 ret = devm_request_threaded_irq(dev, vtg->irq, vtg_irq, 366 vtg_irq_thread, IRQF_ONESHOT, 367 dev_name(dev), vtg); 368 if (IS_ERR_VALUE(ret)) { 369 DRM_ERROR("Failed to register VTG interrupt\n"); 370 return ret; 371 } 372 } 373 374 vtg_register(vtg); 375 platform_set_drvdata(pdev, vtg); 376 377 DRM_INFO("%s %s\n", __func__, dev_name(vtg->dev)); 378 379 return 0; 380 } 381 382 static int vtg_remove(struct platform_device *pdev) 383 { 384 return 0; 385 } 386 387 static const struct of_device_id vtg_of_match[] = { 388 { .compatible = "st,vtg", }, 389 { /* sentinel */ } 390 }; 391 MODULE_DEVICE_TABLE(of, vtg_of_match); 392 393 struct platform_driver sti_vtg_driver = { 394 .driver = { 395 .name = "sti-vtg", 396 .owner = THIS_MODULE, 397 .of_match_table = vtg_of_match, 398 }, 399 .probe = vtg_probe, 400 .remove = vtg_remove, 401 }; 402 403 MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); 404 MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); 405 MODULE_LICENSE("GPL"); 406