cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sti_vtg.c (11839B)


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