-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Video Traffic Advance Communication Rx and Tx drivers are designed for inter-die communication. Signed-off-by: Benjamin Gaignard <benjamin.gaignard@linaro.org> Reviewed-by: Rob Clark <robdclark@gmail.com>
- Loading branch information
Benjamin Gaignard
committed
Jul 30, 2014
1 parent
f2cb314
commit 9ed68fa
Showing
2 changed files
with
217 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
obj-$(CONFIG_DRM_STI) = \ | ||
sti_vtg.o | ||
sti_vtg.o \ | ||
sti_vtac.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,215 @@ | ||
/* | ||
* 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 = {0x2, 0x2, VTAC_5_PPP}; | ||
static const struct sti_vtac_mode vtac_mode_aux = {0x1, 0x0, 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"); |