Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | /* * Copyright (C) STMicroelectronics SA 2014 * Author: Benjamin Gaignard <benjamin.gaignard@st.com> for STMicroelectronics. * License terms: GNU General Public License (GPL), version 2 */ #include <linux/clk.h> #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> #include <linux/platform_device.h> #include <drm/drmP.h> /* registers offset */ #define VTAC_CONFIG 0x00 #define VTAC_RX_FIFO_CONFIG 0x04 #define VTAC_FIFO_CONFIG_VAL 0x04 #define VTAC_SYS_CFG8521 0x824 #define VTAC_SYS_CFG8522 0x828 /* Number of phyts per pixel */ #define VTAC_2_5_PPP 0x0005 #define VTAC_3_PPP 0x0006 #define VTAC_4_PPP 0x0008 #define VTAC_5_PPP 0x000A #define VTAC_6_PPP 0x000C #define VTAC_13_PPP 0x001A #define VTAC_14_PPP 0x001C #define VTAC_15_PPP 0x001E #define VTAC_16_PPP 0x0020 #define VTAC_17_PPP 0x0022 #define VTAC_18_PPP 0x0024 /* enable bits */ #define VTAC_ENABLE 0x3003 #define VTAC_TX_PHY_ENABLE_CLK_PHY BIT(0) #define VTAC_TX_PHY_ENABLE_CLK_DLL BIT(1) #define VTAC_TX_PHY_PLL_NOT_OSC_MODE BIT(3) #define VTAC_TX_PHY_RST_N_DLL_SWITCH BIT(4) #define VTAC_TX_PHY_PROG_N3 BIT(9) /** * VTAC mode structure * * @vid_in_width: Video Data Resolution * @phyts_width: Width of phyt buses(phyt low and phyt high). * @phyts_per_pixel: Number of phyts sent per pixel */ struct sti_vtac_mode { u32 vid_in_width; u32 phyts_width; u32 phyts_per_pixel; }; static const struct sti_vtac_mode vtac_mode_main = { .vid_in_width = 0x2, .phyts_width = 0x2, .phyts_per_pixel = VTAC_5_PPP, }; static const struct sti_vtac_mode vtac_mode_aux = { .vid_in_width = 0x1, .phyts_width = 0x0, .phyts_per_pixel = VTAC_17_PPP, }; /** * VTAC structure * * @dev: pointer to device structure * @regs: ioremapped registers for RX and TX devices * @phy_regs: phy registers for TX device * @clk: clock * @mode: main or auxillary configuration mode */ struct sti_vtac { struct device *dev; void __iomem *regs; void __iomem *phy_regs; struct clk *clk; const struct sti_vtac_mode *mode; }; static void sti_vtac_rx_set_config(struct sti_vtac *vtac) { u32 config; /* Enable VTAC clock */ if (clk_prepare_enable(vtac->clk)) DRM_ERROR("Failed to prepare/enable vtac_rx clock.\n"); writel(VTAC_FIFO_CONFIG_VAL, vtac->regs + VTAC_RX_FIFO_CONFIG); config = VTAC_ENABLE; config |= vtac->mode->vid_in_width << 4; config |= vtac->mode->phyts_width << 16; config |= vtac->mode->phyts_per_pixel << 23; writel(config, vtac->regs + VTAC_CONFIG); } static void sti_vtac_tx_set_config(struct sti_vtac *vtac) { u32 phy_config; u32 config; /* Enable VTAC clock */ if (clk_prepare_enable(vtac->clk)) DRM_ERROR("Failed to prepare/enable vtac_tx clock.\n"); /* Configure vtac phy */ phy_config = 0x00000000; writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8522); phy_config = VTAC_TX_PHY_ENABLE_CLK_PHY; writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521); phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521); phy_config |= VTAC_TX_PHY_PROG_N3; writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521); phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521); phy_config |= VTAC_TX_PHY_ENABLE_CLK_DLL; writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521); phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521); phy_config |= VTAC_TX_PHY_RST_N_DLL_SWITCH; writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521); phy_config = readl(vtac->phy_regs + VTAC_SYS_CFG8521); phy_config |= VTAC_TX_PHY_PLL_NOT_OSC_MODE; writel(phy_config, vtac->phy_regs + VTAC_SYS_CFG8521); /* Configure vtac tx */ config = VTAC_ENABLE; config |= vtac->mode->vid_in_width << 4; config |= vtac->mode->phyts_width << 16; config |= vtac->mode->phyts_per_pixel << 23; writel(config, vtac->regs + VTAC_CONFIG); } static const struct of_device_id vtac_of_match[] = { { .compatible = "st,vtac-main", .data = &vtac_mode_main, }, { .compatible = "st,vtac-aux", .data = &vtac_mode_aux, }, { /* end node */ } }; MODULE_DEVICE_TABLE(of, vtac_of_match); static int sti_vtac_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; const struct of_device_id *id; struct sti_vtac *vtac; struct resource *res; vtac = devm_kzalloc(dev, sizeof(*vtac), GFP_KERNEL); if (!vtac) return -ENOMEM; vtac->dev = dev; id = of_match_node(vtac_of_match, np); if (!id) return -ENOMEM; vtac->mode = id->data; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { DRM_ERROR("Invalid resource\n"); return -ENOMEM; } vtac->regs = devm_ioremap_resource(dev, res); if (IS_ERR(vtac->regs)) return PTR_ERR(vtac->regs); vtac->clk = devm_clk_get(dev, "vtac"); if (IS_ERR(vtac->clk)) { DRM_ERROR("Cannot get vtac clock\n"); return PTR_ERR(vtac->clk); } res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (res) { vtac->phy_regs = devm_ioremap_nocache(dev, res->start, resource_size(res)); sti_vtac_tx_set_config(vtac); } else { sti_vtac_rx_set_config(vtac); } platform_set_drvdata(pdev, vtac); DRM_INFO("%s %s\n", __func__, dev_name(vtac->dev)); return 0; } static int sti_vtac_remove(struct platform_device *pdev) { return 0; } struct platform_driver sti_vtac_driver = { .driver = { .name = "sti-vtac", .owner = THIS_MODULE, .of_match_table = vtac_of_match, }, .probe = sti_vtac_probe, .remove = sti_vtac_remove, }; module_platform_driver(sti_vtac_driver); MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>"); MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver"); MODULE_LICENSE("GPL"); |