#include <linux/of.h>
#endif
+#if defined(CONFIG_DEBUG_FS)
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#endif
+
/*#define EDP_BIST_MODE*/
+/*#define SW_LT*/
+static struct rk32_edp *rk32_edp;
+
+static int rk32_edp_clk_enable(struct rk32_edp *edp)
+{
+ if (!edp->clk_on) {
+ clk_prepare_enable(edp->pd);
+ clk_prepare_enable(edp->pclk);
+ clk_prepare_enable(edp->clk_edp);
+ clk_prepare_enable(edp->clk_24m);
+ edp->clk_on = true;
+ }
+
+ return 0;
+}
+
+static int rk32_edp_clk_disable(struct rk32_edp *edp)
+{
+ if (edp->clk_on) {
+ clk_disable_unprepare(edp->pclk);
+ clk_disable_unprepare(edp->clk_edp);
+ clk_disable_unprepare(edp->clk_24m);
+ clk_disable_unprepare(edp->pd);
+ edp->clk_on = false;
+ }
+
+ return 0;
+}
+
+static int rk32_edp_pre_init(void)
+{
+ u32 val;
+ val = GRF_EDP_REF_CLK_SEL_INTER | (GRF_EDP_REF_CLK_SEL_INTER << 16);
+ writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_SOC_CON12);
+
+ val = 0x80008000;
+ writel_relaxed(val, RK_CRU_VIRT + 0x0d0); /*select 24m*/
+ dsb();
+ val = 0x80008000;
+ writel_relaxed(val, RK_CRU_VIRT + 0x01d0); /*reset edp*/
+ dsb();
+ udelay(1);
+ val = 0x80000000;
+ writel_relaxed(val, RK_CRU_VIRT + 0x01d0);
+ dsb();
+ udelay(1);
+ return 0;
+}
static int rk32_edp_init_edp(struct rk32_edp *edp)
{
+ struct rk_screen *screen = &edp->screen;
+ u32 val = 0;
+
+ rk_fb_get_prmry_screen(screen);
+ if (screen->lcdc_id == 1) /*select lcdc*/
+ val = EDP_SEL_VOP_LIT | (EDP_SEL_VOP_LIT << 16);
+ else
+ val = EDP_SEL_VOP_LIT << 16;
+ writel_relaxed(val, RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
+
rk32_edp_reset(edp);
- rk32_edp_init_analog_param(edp);
+ rk32_edp_init_refclk(edp);
rk32_edp_init_interrupt(edp);
-
rk32_edp_enable_sw_function(edp);
-
rk32_edp_init_analog_func(edp);
-
rk32_edp_init_hpd(edp);
rk32_edp_init_aux(edp);
return 0;
}
+#if 0
static int rk32_edp_detect_hpd(struct rk32_edp *edp)
{
int timeout_loop = 0;
return 0;
}
-
+#endif
static int rk32_edp_read_edid(struct rk32_edp *edp)
{
unsigned char edid[EDID_LENGTH * 2];
*/
/* Read Extension Flag, Number of 128-byte EDID extension blocks */
- retval = rk32_edp_read_byte_from_i2c(edp, EDID_ADDR, EDID_EXTENSION_FLAG,
- &extend_block);
+ retval = rk32_edp_read_byte_from_i2c(edp,
+ EDID_ADDR, EDID_EXTENSION_FLAG, &extend_block);
if (retval < 0) {
dev_err(edp->dev, "EDID extension flag failed!\n");
return -EIO;
dev_dbg(edp->dev, "EDID data includes a single extension!\n");
/* Read EDID data */
- retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDID_HEADER,
- EDID_LENGTH, &edid[EDID_HEADER]);
+ retval = rk32_edp_read_bytes_from_i2c(edp,
+ EDID_ADDR, EDID_HEADER,
+ EDID_LENGTH, &edid[EDID_HEADER]);
if (retval != 0) {
dev_err(edp->dev, "EDID Read failed!\n");
return -EIO;
}
/* Read additional EDID data */
- retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDID_LENGTH,
- EDID_LENGTH, &edid[EDID_LENGTH]);
+ retval = rk32_edp_read_bytes_from_i2c(edp,
+ EDID_ADDR, EDID_LENGTH,
+ EDID_LENGTH, &edid[EDID_LENGTH]);
if (retval != 0) {
dev_err(edp->dev, "EDID Read failed!\n");
return -EIO;
return 0;
}
- retval = rk32_edp_read_byte_from_dpcd(edp, DPCD_TEST_REQUEST,
- &test_vector);
+ retval = rk32_edp_read_byte_from_dpcd(edp,
+ DPCD_TEST_REQUEST, &test_vector);
if (retval < 0) {
dev_err(edp->dev, "DPCD EDID Read failed!\n");
return retval;
dev_info(edp->dev, "EDID data does not include any extensions.\n");
/* Read EDID data */
- retval = rk32_edp_read_bytes_from_i2c(edp, EDID_ADDR, EDID_HEADER,
- EDID_LENGTH, &edid[EDID_HEADER]);
+ retval = rk32_edp_read_bytes_from_i2c(edp,
+ EDID_ADDR, EDID_HEADER,
+ EDID_LENGTH, &edid[EDID_HEADER]);
if (retval != 0) {
dev_err(edp->dev, "EDID Read failed!\n");
return -EIO;
return 0;
}
- retval = rk32_edp_read_byte_from_dpcd(edp,DPCD_TEST_REQUEST,
- &test_vector);
+ retval = rk32_edp_read_byte_from_dpcd(edp,
+ DPCD_TEST_REQUEST, &test_vector);
if (retval < 0) {
dev_err(edp->dev, "DPCD EDID Read failed!\n");
return retval;
}
}
}
-
+ fb_edid_to_monspecs(edid, &edp->specs);
dev_err(edp->dev, "EDID Read success!\n");
return 0;
}
+#if 0
static int rk32_edp_handle_edid(struct rk32_edp *edp)
{
u8 buf[12];
if (retval < 0)
return retval;
+ for (i = 0; i < 12; i++)
+ dev_info(edp->dev, "%d:>>0x%02x\n", i, buf[i]);
/* Read EDID */
for (i = 0; i < 3; i++) {
retval = rk32_edp_read_edid(edp);
return retval;
}
+
static int rk32_edp_enable_rx_to_enhanced_mode(struct rk32_edp *edp,
bool enable)
{
}*/
}
+
static int rk32_edp_is_enhanced_mode_available(struct rk32_edp *edp)
{
u8 data;
return DPCD_ENHANCED_FRAME_CAP(data);
}
+
static void rk32_edp_disable_rx_zmux(struct rk32_edp *edp)
{
/*rk32_edp_write_byte_to_dpcd(edp,
return 0;
}
+#endif
+#if defined(SW_LT)
static int rk32_edp_training_pattern_dis(struct rk32_edp *edp)
{
int retval;
rk32_edp_reduce_link_rate(edp);
return -EIO;
}
-
+#endif
static int rk32_edp_get_max_rx_bandwidth(struct rk32_edp *edp,
u8 *bandwidth)
{
u8 data;
- int retval;
+ int retval = 0;
/*
* For DP rev.1.1, Maximum link rate of Main Link lanes
retval = rk32_edp_read_byte_from_dpcd(edp,
DPCD_MAX_LINK_RATE, &data);
if (retval < 0)
- return retval;
+ *bandwidth = 0;
+ else
+ *bandwidth = data;
+ return retval;
- *bandwidth = data;
- return 0;
}
static int rk32_edp_get_max_rx_lane_count(struct rk32_edp *edp,
retval = rk32_edp_read_byte_from_dpcd(edp,
DPCD_MAX_LANE_CNT, &data);
if (retval < 0)
- return retval;
-
- *lane_count = DPCD_MAX_LANE_COUNT(data);
- return 0;
+ *lane_count = 0;
+ else
+ *lane_count = DPCD_MAX_LANE_COUNT(data);
+ return retval;
}
-static int rk32_edp_init_training(struct rk32_edp *edp,
- enum link_lane_count_type max_lane,
- u32 max_rate)
+static int rk32_edp_init_training(struct rk32_edp *edp)
{
int retval;
*/
rk32_edp_reset_macro(edp);
-
- retval = rk32_edp_get_max_rx_bandwidth(edp, &edp->link_train.link_rate);
- if (retval < 0)
- return retval;
- retval = rk32_edp_get_max_rx_lane_count(edp, &edp->link_train.lane_count);
- if (retval < 0)
- return retval;
+ retval = rk32_edp_get_max_rx_bandwidth(edp,
+ &edp->link_train.link_rate);
+ retval = rk32_edp_get_max_rx_lane_count(edp,
+ &edp->link_train.lane_count);
dev_info(edp->dev, "max link rate:%d.%dGps max number of lanes:%d\n",
edp->link_train.link_rate * 27/100,
edp->link_train.link_rate*27%100,
edp->link_train.lane_count);
-
+
if ((edp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
(edp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
- dev_err(edp->dev, "Rx Max Link Rate is abnormal :%x !\n",
- edp->link_train.link_rate);
- edp->link_train.link_rate = LINK_RATE_1_62GBPS;
+ dev_warn(edp->dev, "Rx Max Link Rate is abnormal :%x !"
+ "use default link rate:%d.%dGps\n",
+ edp->link_train.link_rate,
+ edp->video_info.link_rate*27/100,
+ edp->video_info.link_rate*27%100);
+ edp->link_train.link_rate = edp->video_info.link_rate;
}
if (edp->link_train.lane_count == 0) {
- dev_err(edp->dev, "Rx Max Lane count is abnormal :%x !\n",
- edp->link_train.lane_count);
- edp->link_train.lane_count = (u8)LANE_CNT1;
+ dev_err(edp->dev, "Rx Max Lane count is abnormal :%x !"
+ "use default lanes:%d\n",
+ edp->link_train.lane_count,
+ edp->video_info.lane_count);
+ edp->link_train.lane_count = edp->video_info.lane_count;
}
-
- if (edp->link_train.lane_count > max_lane)
- edp->link_train.lane_count = max_lane;
- if (edp->link_train.link_rate > max_rate)
- edp->link_train.link_rate = max_rate;
-
-
rk32_edp_analog_power_ctr(edp, 1);
+
return 0;
}
+#if defined(SW_LT)
static int rk32_edp_sw_link_training(struct rk32_edp *edp)
{
int retval = 0;
return retval;
}
-
+#else
static int rk32_edp_hw_link_training(struct rk32_edp *edp)
{
u32 cnt = 50;
rk32_edp_set_link_bandwidth(edp, edp->link_train.link_rate);
rk32_edp_set_lane_count(edp, edp->link_train.lane_count);
rk32_edp_hw_link_training_en(edp);
- mdelay(1);
val = rk32_edp_wait_hw_lt_done(edp);
while (val) {
if (cnt-- <= 0) {
mdelay(1);
val = rk32_edp_wait_hw_lt_done(edp);
}
-
+
val = rk32_edp_get_hw_lt_status(edp);
if (val)
dev_err(edp->dev, "hw lt err:%d\n", val);
return val;
-
+
}
-static int rk32_edp_set_link_train(struct rk32_edp *edp,
- u32 count,
- u32 bwtype)
+#endif
+
+static int rk32_edp_set_link_train(struct rk32_edp *edp)
{
int retval;
- retval = rk32_edp_init_training(edp, count, bwtype);
+ retval = rk32_edp_init_training(edp);
if (retval < 0)
dev_err(edp->dev, "DP LT init failed!\n");
-#if 0
+#if defined(SW_LT)
retval = rk32_edp_sw_link_training(edp);
#else
retval = rk32_edp_hw_link_training(edp);
return -ETIMEDOUT;
}
- usleep_range(1, 1);
+ udelay(1);
}
/* Set to use the register calculated M/N video */
rk32_edp_set_video_cr_mn(edp, CALCULATED_M, 0, 0);
/* For video bist, Video timing must be generated by register */
+#ifndef EDP_BIST_MODE
rk32_edp_set_video_timing_mode(edp, VIDEO_TIMING_FROM_CAPTURE);
-
+#endif
/* Disable video mute */
rk32_edp_enable_video_mute(edp, 0);
return -ETIMEDOUT;
}
- usleep_range(1000, 1000);
+ mdelay(1);
}
if (retval != 0)
return retval;
}
+#if 0
static int rk32_edp_enable_scramble(struct rk32_edp *edp, bool enable)
{
u8 data;
return 0;
}
+#endif
static irqreturn_t rk32_edp_isr(int irq, void *arg)
{
struct rk32_edp *edp = arg;
+ enum dp_irq_type irq_type;
- dev_info(edp->dev, "rk32_edp_isr\n");
+ irq_type = rk32_edp_get_irq_type(edp);
+ switch (irq_type) {
+ case DP_IRQ_TYPE_HP_CABLE_IN:
+ dev_info(edp->dev, "Received irq - cable in\n");
+ rk32_edp_clear_hotplug_interrupts(edp);
+ break;
+ case DP_IRQ_TYPE_HP_CABLE_OUT:
+ dev_info(edp->dev, "Received irq - cable out\n");
+ rk32_edp_clear_hotplug_interrupts(edp);
+ break;
+ case DP_IRQ_TYPE_HP_CHANGE:
+ /*
+ * We get these change notifications once in a while, but there
+ * is nothing we can do with them. Just ignore it for now and
+ * only handle cable changes.
+ */
+ dev_info(edp->dev, "Received irq - hotplug change; ignoring.\n");
+ rk32_edp_clear_hotplug_interrupts(edp);
+ break;
+ default:
+ dev_err(edp->dev, "Received irq - unknown type!\n");
+ break;
+ }
return IRQ_HANDLED;
}
-static int rk32_edp_enable(struct rk32_edp *edp)
+static int rk32_edp_enable(void)
{
int ret = 0;
- int retry = 0;
-
- if (edp->enabled)
- goto out;
+ struct rk32_edp *edp = rk32_edp;
- edp->enabled = 1;
- clk_prepare_enable(edp->clk_edp);
- clk_prepare_enable(edp->clk_24m);
-edp_phy_init:
-
+ rk32_edp_clk_enable(edp);
+ rk32_edp_pre_init();
rk32_edp_init_edp(edp);
-
-
- ret = rk32_edp_handle_edid(edp);
+ enable_irq(edp->irq);
+ /*ret = rk32_edp_handle_edid(edp);
if (ret) {
dev_err(edp->dev, "unable to handle edid\n");
- goto out;
+ //goto out;
}
- rk32_edp_disable_rx_zmux(edp);
-
ret = rk32_edp_enable_scramble(edp, 0);
if (ret) {
dev_err(edp->dev, "unable to set scramble\n");
- goto out;
+ //goto out;
}
ret = rk32_edp_enable_rx_to_enhanced_mode(edp, 0);
if (ret) {
dev_err(edp->dev, "unable to set enhanced mode\n");
- goto out;
+ //goto out;
}
- rk32_edp_enable_enhanced_mode(edp, 0);
+ rk32_edp_enable_enhanced_mode(edp, 1);*/
-
- rk32_edp_rx_control(edp,0);
+ ret = rk32_edp_set_link_train(edp);
+ if (ret)
+ dev_err(edp->dev, "link train failed!\n");
+ else
+ dev_info(edp->dev, "link training success.\n");
- /* Link Training */
- ret = rk32_edp_set_link_train(edp, LANE_CNT4, LINK_RATE_2_70GBPS);
- if (ret) {
- dev_err(edp->dev, "link train failed\n");
- goto out;
- }
-
- /* Rx data enable */
- rk32_edp_rx_control(edp,1);
-
- rk32_edp_set_lane_count(edp, edp->video_info.lane_count);
- rk32_edp_set_link_bandwidth(edp, edp->video_info.link_rate);
+ rk32_edp_set_lane_count(edp, edp->link_train.lane_count);
+ rk32_edp_set_link_bandwidth(edp, edp->link_train.link_rate);
+ rk32_edp_init_video(edp);
#ifdef EDP_BIST_MODE
rk32_edp_bist_cfg(edp);
-#else
- rk32_edp_init_video(edp);
+#endif
ret = rk32_edp_config_video(edp, &edp->video_info);
- if (ret) {
+ if (ret)
dev_err(edp->dev, "unable to config video\n");
- goto out;
- }
-#endif
- return 0;
+ return ret;
-out:
- if (retry < 3) {
- retry++;
- goto edp_phy_init;
- }
-
- dev_err(edp->dev, "DP LT exceeds max retry count");
- return ret;
}
-
-static void rk32_edp_disable(struct rk32_edp *edp)
-{
- if (!edp->enabled)
- return ;
- edp->enabled = 0;
+static int rk32_edp_disable(void)
+{
+ struct rk32_edp *edp = rk32_edp;
+ disable_irq(edp->irq);
rk32_edp_reset(edp);
rk32_edp_analog_power_ctr(edp, 0);
+ rk32_edp_clk_disable(edp);
- clk_disable(edp->clk_24m);
- clk_disable(edp->clk_edp);
+ return 0;
}
+static struct rk_fb_trsm_ops trsm_edp_ops = {
+ .enable = rk32_edp_enable,
+ .disable = rk32_edp_disable,
+};
+
-static void rk32_edp_init(struct rk32_edp *edp)
+#if defined(CONFIG_DEBUG_FS)
+
+static int edp_dpcd_debugfs_show(struct seq_file *s, void *v)
{
+ int i = 0;
+ unsigned char buf[12];
+ struct rk32_edp *edp = s->private;
+ if (!edp) {
+ dev_err(edp->dev, "no edp device!\n");
+ return -ENODEV;
+ }
+
+
+ rk32_edp_read_bytes_from_dpcd(edp,
+ DPCD_SYMBOL_ERR_CONUT_LANE0, 12, buf);
+ for (i = 0; i < 12; i++)
+ seq_printf(s, "0x%02x>>0x%02x\n", 0x210 + i, buf[i]);
+ return 0;
+}
- rk32_edp_enable(edp);
+static ssize_t edp_dpcd_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ return count;
}
+
+static int edp_edid_debugfs_show(struct seq_file *s, void *v)
+{
+ struct rk32_edp *edp = s->private;
+ if (!edp) {
+ dev_err(edp->dev, "no edp device!\n");
+ return -ENODEV;
+ }
+ rk32_edp_read_edid(edp);
+ seq_puts(s, "edid");
+ return 0;
+}
+
+static ssize_t edp_edid_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ struct rk32_edp *edp = ((struct seq_file *)file->private_data)->private;
+ if (!edp) {
+ dev_err(edp->dev, "no edp device!\n");
+ return -ENODEV;
+ }
+ rk32_edp_disable();
+ rk32_edp_enable();
+ return count;
+}
+
+static int edp_reg_debugfs_show(struct seq_file *s, void *v)
+{
+ int i = 0;
+ struct rk32_edp *edp = s->private;
+ if (!edp) {
+ dev_err(edp->dev, "no edp device!\n");
+ return -ENODEV;
+ }
+
+ for (i = 0; i < 0x284; i++) {
+ if (!(i%4))
+ seq_printf(s, "\n%08x: ", i*4);
+ seq_printf(s, "%08x ", readl(edp->regs + i*4));
+ }
+ return 0;
+}
+
+static ssize_t edp_reg_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+ return count;
+}
+
+#define EDP_DEBUG_ENTRY(name) \
+static int edp_##name##_debugfs_open(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, edp_##name##_debugfs_show, inode->i_private); \
+} \
+\
+static const struct file_operations edp_##name##_debugfs_fops = { \
+ .owner = THIS_MODULE, \
+ .open = edp_##name##_debugfs_open, \
+ .read = seq_read, \
+ .write = edp_##name##_write, \
+ .llseek = seq_lseek, \
+ .release = single_release, \
+}
+
+EDP_DEBUG_ENTRY(dpcd);
+EDP_DEBUG_ENTRY(edid);
+EDP_DEBUG_ENTRY(reg);
+#endif
+
static int rk32_edp_probe(struct platform_device *pdev)
{
struct rk32_edp *edp;
edp->video_info.ycbcr_coeff = COLOR_YCBCR601;
edp->video_info.color_depth = COLOR_8;
- edp->video_info.link_rate = LINK_RATE_2_70GBPS;
+ edp->video_info.link_rate = LINK_RATE_1_62GBPS;
edp->video_info.lane_count = LANE_CNT4;
rk_fb_get_prmry_screen(&edp->screen);
if (edp->screen.type != SCREEN_EDP) {
}
platform_set_drvdata(pdev, edp);
dev_set_name(edp->dev, "rk32-edp");
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
edp->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(edp->regs)) {
dev_err(&pdev->dev, "ioremap reg failed\n");
return PTR_ERR(edp->regs);
}
+
+ edp->pd = devm_clk_get(&pdev->dev, "pd_edp");
+ if (IS_ERR(edp->pd))
+ dev_err(&pdev->dev, "cannot get pd\n");
+ edp->clk_edp = devm_clk_get(&pdev->dev, "clk_edp");
+ if (IS_ERR(edp->clk_edp)) {
+ dev_err(&pdev->dev, "cannot get clk_edp\n");
+ return PTR_ERR(edp->clk_edp);
+ }
+
+ edp->clk_24m = devm_clk_get(&pdev->dev, "clk_edp_24m");
+ if (IS_ERR(edp->clk_24m)) {
+ dev_err(&pdev->dev, "cannot get clk_edp_24m\n");
+ return PTR_ERR(edp->clk_24m);
+ }
+
+ edp->pclk = devm_clk_get(&pdev->dev, "pclk_edp");
+ if (IS_ERR(edp->pclk)) {
+ dev_err(&pdev->dev, "cannot get pclk\n");
+ return PTR_ERR(edp->pclk);
+ }
+ rk32_edp_clk_enable(edp);
+ if (!support_uboot_display())
+ rk32_edp_pre_init();
+ edp->irq = platform_get_irq(pdev, 0);
+ if (edp->irq < 0) {
+ dev_err(&pdev->dev, "cannot find IRQ\n");
+ return edp->irq;
+ }
ret = devm_request_irq(&pdev->dev, edp->irq, rk32_edp_isr, 0,
dev_name(&pdev->dev), edp);
if (ret) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", edp->irq);
return ret;
}
-
- rk32_edp_init(edp);
+ disable_irq_nosync(edp->irq);
+ if (!support_uboot_display())
+ rk32_edp_clk_disable(edp);
+ rk32_edp = edp;
+ rk_fb_trsm_ops_register(&trsm_edp_ops, SCREEN_EDP);
+#if defined(CONFIG_DEBUG_FS)
+ edp->debugfs_dir = debugfs_create_dir("edp", NULL);
+ if (IS_ERR(edp->debugfs_dir)) {
+ dev_err(edp->dev, "failed to create debugfs dir for edp!\n");
+ } else {
+ debugfs_create_file("dpcd", S_IRUSR, edp->debugfs_dir,
+ edp, &edp_dpcd_debugfs_fops);
+ debugfs_create_file("edid", S_IRUSR, edp->debugfs_dir,
+ edp, &edp_edid_debugfs_fops);
+ debugfs_create_file("reg", S_IRUSR, edp->debugfs_dir,
+ edp, &edp_reg_debugfs_fops);
+ }
+
+#endif
dev_info(&pdev->dev, "rk32 edp driver probe success\n");
return 0;
#if defined(CONFIG_OF)
static const struct of_device_id rk32_edp_dt_ids[] = {
- {.compatible = "rockchip, rk32-edp",},
+ {.compatible = "rockchip,rk32-edp",},
{}
};