/ {
compatible = "rockchip,rk3128";
- backlight {
+ backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm0 0 25000>;
brightness-levels = <0 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 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255>;
&lcdc {
status = "okay";
+ backlight = <&backlight>;
pinctrl-names = "default", "gpio";
pinctrl-0 = <&lcdc0_lcdc>;
pinctrl-1 = <&lcdc0_gpio>;
if((host->cmd->arg & (0x1 << 31)) == 1) /* secure erase */
se_flag = 0x1;
- if (((this_card->ext_csd.erase_group_def) & 0x1) == 1) ;
+ if (((this_card->ext_csd.erase_group_def) & 0x1) == 1)
se_flag ? (timeout = (this_card->ext_csd.hc_erase_timeout) *
300000 * (this_card->ext_csd.sec_erase_mult)) :
(timeout = (this_card->ext_csd.hc_erase_timeout) * 300000);
/* Stop edma when rountine card triggered */
if(cpu_is_rk3036() || cpu_is_rk312x())
- if(host->dma_ops->stop)
+ if(host->dma_ops && host->dma_ops->stop)
host->dma_ops->stop(host);
while (present != slot->last_detect_state) {
/*only for sdmmc controller*/
if (host->mmc->restrict_caps & RESTRICT_CARD_TYPE_SD) {
host->mmc->rescan_disable = 1;
- if (!(cpu_is_rk312x() || cpu_is_rk3036())) {
- if (cancel_delayed_work_sync(&host->mmc->detect))
- wake_unlock(&host->mmc->detect_wake_lock);
- } else {
- /* we find dpm suspend timeout for mmc cancel this work sync way,
- actually just workaround this for low end platform with
- gpio-debounce detect method.
- */
- if (cancel_delayed_work(&host->mmc->detect))
- wake_unlock(&host->mmc->detect_wake_lock);
- }
+
+ if(cancel_delayed_work(&host->mmc->detect))
+ wake_unlock(&host->mmc->detect_wake_lock);
disable_irq(host->irq);
if (pinctrl_select_state(host->pinctrl, host->pins_idle) < 0)
#include <linux/of_irq.h>
#include "rk3036_hdmi.h"
#include "rk3036_hdmi_hw.h"
-
+static unsigned int rk3036_hdmi_support_vic[] = {
+ HDMI_720X480P_60HZ_VIC,
+ HDMI_720X480I_60HZ_VIC,
+ HDMI_720X576P_50HZ_VIC,
+ HDMI_720X576I_50HZ_VIC,
+ HDMI_1280X720P_50HZ_VIC,
+ HDMI_1280X720P_60HZ_VIC,
+ HDMI_1920X1080P_50HZ_VIC,
+ HDMI_1920X1080I_50HZ_VIC,
+ HDMI_1920X1080P_60HZ_VIC,
+ HDMI_1920X1080I_60HZ_VIC
+};
static int __maybe_unused rk3036_hdmi_show_reg(struct hdmi *hdmi_drv)
{
int i = 0;
#endif
}
- /* clear EDID interrupt reg */
- hdmi_writel(hdmi_dev, INTERRUPT_STATUS1,
- m_INT_EDID_READY);
-
if ((checksum & 0xff) == 0) {
ret = 0;
hdmi_dbg(hdmi_drv->dev,
}
/*close edid irq*/
hdmi_writel(hdmi_dev, INTERRUPT_MASK1, 0);
+ /* clear EDID interrupt reg */
+ hdmi_writel(hdmi_dev, INTERRUPT_STATUS1,
+ m_INT_EDID_READY);
+
enable_irq(hdmi_drv->irq);
return ret;
struct rk_hdmi_device *hdmi_dev = container_of(hdmi_drv,
struct rk_hdmi_device,
driver);
+ hdmi_readl(hdmi_dev, INTERRUPT_STATUS1, &interrupt);
+ if(interrupt) {
+ hdmi_writel(hdmi_dev, INTERRUPT_STATUS1, interrupt);
+ dev_info(hdmi_drv->dev, "Clear edid irq.\n");
+ }
+
hdmi_readl(hdmi_dev, HDMI_STATUS, &interrupt);
if(interrupt) {
hdmi_writel(hdmi_dev, HDMI_STATUS, interrupt);
hdmi_drv->read_edid = rk3036_hdmi_read_edid;
hdmi_drv->insert = rk3036_hdmi_insert;
hdmi_drv->ops = &hdmi_drv_ops;
+ hdmi_drv->support_vic = rk3036_hdmi_support_vic;
+ hdmi_drv->support_vic_num = ARRAY_SIZE(rk3036_hdmi_support_vic);
if (!hdmi_drv->uboot_logo) {
rk3036_hdmi_reset_pclk();
#include <linux/interrupt.h>
#include "rk3288_hdmi_hw.h"
+static unsigned int rk3288_hdmi_support_vic[] = {
+ HDMI_720X480P_60HZ_VIC,
+ HDMI_720X576P_50HZ_VIC,
+ HDMI_1280X720P_50HZ_VIC,
+ HDMI_1280X720P_60HZ_VIC,
+ HDMI_1920X1080P_50HZ_VIC,
+ HDMI_1920X1080P_60HZ_VIC,
+ HDMI_3840X2160P_24HZ_VIC,
+ HDMI_3840X2160P_25HZ_VIC,
+ HDMI_3840X2160P_30HZ_VIC,
+ HDMI_3840X2160P_50HZ_VIC,
+ HDMI_3840X2160P_60HZ_VIC
+};
static const struct phy_mpll_config_tab PHY_MPLL_TABLE[] = { /* opmode: 0:HDMI1.4 1:HDMI2.0 */
/* pixclock pixrepet colordepth prepdiv tmdsmhl opmode fbdiv2 fbdiv1 ref_cntrl nctrl propctrl intctrl gmpctrl */
{27000000, 0, HDMI_COLOR_DEPTH_8BIT, 0, 0, 0, 2, 3, 0, 3, 7, 0, 3},
hdmi_drv->config_audio = rk3288_hdmi_config_audio;
hdmi_drv->detect_hotplug = rk3288_hdmi_detect_hotplug;
hdmi_drv->read_edid = rk3288_hdmi_read_edid;
+ hdmi_drv->support_vic = rk3288_hdmi_support_vic;
+ hdmi_drv->support_vic_num = ARRAY_SIZE(rk3288_hdmi_support_vic);
rk3288_hdmi_reset(hdmi_drv);
void (*cec_set_device_pa)(int);
int (*cec_enumerate)(void);
struct rk_hdmi_drv_ops *ops;
+ unsigned int *support_vic;
+ int support_vic_num;
};
#define hdmi_err(dev, format, arg...) \
}
return -1;
}
+int hdmi_check_support_videomode(int vic)
+{
+ int i, support = 0;
+ if (m_hdmi_drv->support_vic_num == 0)
+ return 1;
+
+ for (i=0; i<m_hdmi_drv->support_vic_num; i++) {
+ if (m_hdmi_drv->support_vic[i] == vic) {
+ support = 1;
+ break;
+ }
+ }
+ if(i >= m_hdmi_drv->support_vic_num)
+ support = 0;
+ return support;
+}
/**
* hdmi_add_videomode: adds videomode entry to modelist
for (i = 0; i < ARRAY_SIZE(hdmi_mode); i++) {
m = (struct fb_videomode *)&hdmi_mode[i];
if (fb_mode_is_equal(m, mode)) {
- found = 1;
+ if(hdmi_check_support_videomode(m->flag))
+ found = 1;
break;
}
}
#include <dt-bindings/clock/rk_system_status.h>
#include <linux/rockchip-iovmm.h>
#include "rk312x_lcdc.h"
+#include <linux/rockchip/dvfs.h>
static int dbg_thresd;
module_param(dbg_thresd, int, S_IRUGO | S_IWUSR);
return (u32)sclk_freq;
}
-#define SCLK_PLL_LIMIT 594000000
+#define SCLK_PLL_LIMIT 594000000
+#define GPU_FREQ_MAX_LIMIT 297000000
+#define GPU_FREQ_NEED 400000000
+
static u32 calc_sclk_pll_freq(u32 sclk_freq)
{
-#define ACCURACY_LEV 100
- u32 pll_freq = 0;
- u32 decimal_num = 0;
- u16 max_multi_num = 0, multi_num = 0, remainder_num = 0;
- u32 less_delta = 0, greater_delta = 0;
-
- if (sclk_freq == 0)
- return 0;
+ u32 multi_num;
- max_multi_num = SCLK_PLL_LIMIT / sclk_freq;
- decimal_num = (sclk_freq / (1000000 / ACCURACY_LEV)) % ACCURACY_LEV;
- multi_num = ACCURACY_LEV / decimal_num;
-
- if (multi_num > max_multi_num) {
- multi_num = max_multi_num;
- } else if (decimal_num != 0) {
- remainder_num = ACCURACY_LEV % decimal_num;
- if (remainder_num != 0) {
- less_delta = ACCURACY_LEV - (decimal_num * multi_num);
- greater_delta = decimal_num * (multi_num + 1) - ACCURACY_LEV;
- multi_num = (less_delta < greater_delta) ? multi_num : (multi_num + 1);
- }
+ if (sclk_freq < (SCLK_PLL_LIMIT / 10)) {
+ return (sclk_freq * 10);
+ } else {
+ multi_num = GPU_FREQ_NEED / sclk_freq;
+ return (sclk_freq * multi_num);
}
-
- pll_freq = sclk_freq * multi_num;
- return pll_freq;
}
static int calc_dsp_frm_vst_hst(struct rk_screen *src,
T_frm_st = (T_BP_in + T_Delta - T_BP_out);
else
T_frm_st = Tin - (T_BP_out - (T_BP_in + T_Delta));
- printk("T_in=%lld,T_BP_in=%lld,T_Delta=%lld,T_BP_out=%lld\n",Tin,T_BP_in,T_Delta,T_BP_out);
- printk("T_frm_st=%lld\n",T_frm_st);
- printk("src_pixclock=%d\n,dst_pixclock=%d\n",src_pixclock,dst_pixclock);
/* (T_frm_st = scl_vst * src_htotal * src_pixclock + scl_hst * src_pixclock) */
- temp = do_div(T_frm_st, src_htotal * src_pixclock);
+ temp = do_div(T_frm_st, src_pixclock);
+ temp = do_div(T_frm_st, src_htotal);
+ dst->scl_hst = temp - 1;
dst->scl_vst = T_frm_st;
- do_div(temp, src_pixclock);
- dst->scl_hst = temp;
- printk("dst_frame_hst=%d,dst_frame_vst=%d\n",dst->scl_hst,dst->scl_vst);
+
return 0;
}
struct rk_screen *dst;
struct lcdc_device *lcdc_dev = container_of(dev_drv,
struct lcdc_device, driver);
+ struct dvfs_node *gpu_clk = clk_get_dvfs_node("clk_gpu");
if (unlikely(!lcdc_dev->clk_on))
return 0;
spin_lock(&lcdc_dev->reg_lock);
lcdc_msk_reg(lcdc_dev, SCALER_CTRL,
m_SCALER_EN | m_SCALER_OUT_ZERO | m_SCALER_OUT_EN,
- v_SCALER_EN(0) | v_SCALER_OUT_ZERO(0) | v_SCALER_OUT_EN(0));
+ v_SCALER_EN(0) | v_SCALER_OUT_ZERO(1) | v_SCALER_OUT_EN(0));
+ lcdc_cfg_done(lcdc_dev);
spin_unlock(&lcdc_dev->reg_lock);
if (lcdc_dev->sclk_on) {
clk_disable_unprepare(lcdc_dev->sclk);
lcdc_dev->sclk_on = false;
}
+
+ /* switch pll freq as default when sclk is no used */
+ if (clk_get_rate(lcdc_dev->pll_sclk) != GPU_FREQ_NEED) {
+ dvfs_clk_enable_limit(gpu_clk, GPU_FREQ_MAX_LIMIT,
+ GPU_FREQ_MAX_LIMIT);
+ clk_set_rate(lcdc_dev->pll_sclk, GPU_FREQ_NEED);
+ dvfs_clk_enable_limit(gpu_clk, 0, -1);
+ }
dev_dbg(lcdc_dev->dev, "%s: disable\n", __func__);
return 0;
}
clk_prepare_enable(lcdc_dev->sclk);
lcdc_dev->s_pixclock = calc_sclk_freq(src, dst);
pll_freq = calc_sclk_pll_freq(lcdc_dev->s_pixclock);
+
+ /* limit gpu freq */
+ dvfs_clk_enable_limit(gpu_clk, GPU_FREQ_MAX_LIMIT, GPU_FREQ_MAX_LIMIT);
+ /* set pll freq */
clk_set_rate(lcdc_dev->pll_sclk, pll_freq);
+ /* cancel limit gpu freq */
+ dvfs_clk_enable_limit(gpu_clk, 0, -1);
+
clk_set_rate(lcdc_dev->sclk, lcdc_dev->s_pixclock);
lcdc_dev->sclk_on = true;
dev_info(lcdc_dev->dev, "%s:sclk=%d\n", __func__,
v_SW_OVERLAY_MODE(dev_drv->overlay_mode));
}
- mask = m_DSP_OUT_FORMAT | m_HSYNC_POL | m_VSYNC_POL |
+ mask = m_HSYNC_POL | m_VSYNC_POL |
m_DEN_POL | m_DCLK_POL;
- val = v_DSP_OUT_FORMAT(face) | v_HSYNC_POL(screen->pin_hsync) |
+ val = v_HSYNC_POL(screen->pin_hsync) |
v_VSYNC_POL(screen->pin_vsync) |
v_DEN_POL(screen->pin_den) |
v_DCLK_POL(screen->pin_dclk);
+
+ if (screen->type != SCREEN_HDMI) {
+ mask |= m_DSP_OUT_FORMAT;
+ val |= v_DSP_OUT_FORMAT(face);
+ }
+
lcdc_msk_reg(lcdc_dev, DSP_CTRL0, mask, val);
mask = m_BG_COLOR | m_DSP_BG_SWAP | m_DSP_RB_SWAP |
return ovl;
}
+static int rk312x_lcdc_dsp_black(struct rk_lcdc_driver *dev_drv, int enable)
+{
+ struct lcdc_device *lcdc_dev = container_of(dev_drv,
+ struct lcdc_device, driver);
+ struct device_node *backlight;
+
+ if (!lcdc_dev->backlight) {
+ backlight = of_parse_phandle(lcdc_dev->dev->of_node, "backlight", 0);
+ if (backlight) {
+ lcdc_dev->backlight = of_find_backlight_by_node(backlight);
+ if (!lcdc_dev->backlight)
+ dev_info(lcdc_dev->dev, "No find backlight device\n");
+ }
+ }
+
+ if (enable) {
+ /* close the backlight */
+ if (lcdc_dev->backlight) {
+ lcdc_dev->backlight->props.power = FB_BLANK_POWERDOWN;
+ backlight_update_status(lcdc_dev->backlight);
+ }
+
+ spin_lock(&lcdc_dev->reg_lock);
+ if (likely(lcdc_dev->clk_on)) {
+ lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_BLACK_EN,
+ v_BLACK_EN(1));
+ lcdc_cfg_done(lcdc_dev);
+ }
+ spin_unlock(&lcdc_dev->reg_lock);
+
+ if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
+ dev_drv->trsm_ops->disable();
+ } else {
+ spin_lock(&lcdc_dev->reg_lock);
+ if (likely(lcdc_dev->clk_on)) {
+ lcdc_msk_reg(lcdc_dev, DSP_CTRL1, m_BLACK_EN,
+ v_BLACK_EN(0));
+ lcdc_cfg_done(lcdc_dev);
+ }
+ spin_unlock(&lcdc_dev->reg_lock);
+ if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
+ dev_drv->trsm_ops->enable();
+ msleep(100);
+ /* open the backlight */
+ if (lcdc_dev->backlight) {
+ lcdc_dev->backlight->props.power = FB_BLANK_UNBLANK;
+ backlight_update_status(lcdc_dev->backlight);
+ }
+ }
+
+ return 0;
+}
+
+
static struct rk_lcdc_drv_ops lcdc_drv_ops = {
.open = rk312x_lcdc_open,
.load_screen = rk312x_load_screen,
.set_screen_scaler = rk312x_lcdc_set_scaler,
.set_hwc_lut = rk312x_lcdc_set_hwc_lut,
.set_irq_to_cpu = rk312x_lcdc_set_irq_to_cpu,
+ .dsp_black = rk312x_lcdc_dsp_black,
};
#if 0
static const struct rk_lcdc_drvdata rk3036_lcdc_drvdata = {
rk312x_lcdc_deinit(lcdc_dev);
rk312x_lcdc_clk_disable(lcdc_dev);
rk_disp_pwr_disable(&lcdc_dev->driver);
+
+ if (lcdc_dev->backlight)
+ put_device(&lcdc_dev->backlight->dev);
}
static struct platform_driver rk312x_lcdc_driver = {
u32 s_pixclock;
u32 standby; /* 1:standby,0:work */
+ struct backlight_device *backlight;
};
static inline void lcdc_writel(struct lcdc_device *lcdc_dev, u32 offset, u32 v)
int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
if (win_id >= 0) {
- dev_drv->win[win_id]->logicalstate--;
- if (!dev_drv->win[win_id]->logicalstate) {
- win = dev_drv->win[win_id];
+ win = dev_drv->win[win_id];
+ win->logicalstate--;
+ if (!win->logicalstate) {
info->fix.smem_start = win->reserved;
info->var.xres = dev_drv->screen0->mode.xres;
info->var.yres = dev_drv->screen0->mode.yres;
info->var.vsync_len = dev_drv->screen0->mode.vsync_len;
info->var.hsync_len = dev_drv->screen0->mode.hsync_len;
}
+ info->var.reserved[0] = (__u32)win->area[0].ion_hdl;
}
return 0;
struct ion_handle *handle = (struct ion_handle *)info->var.reserved[0];
struct dma_buf *dma_buf = NULL;
- if (IS_ERR(handle)) {
+ if (handle == NULL || IS_ERR(handle)) {
dev_err(info->device, "failed to get ion handle:%ld\n",
PTR_ERR(handle));
return -ENOMEM;
return 0;
if (rk_fb->disp_mode == ONE_DUAL) {
- if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
- dev_drv->trsm_ops->disable();
+ if (dev_drv->ops->dsp_black)
+ dev_drv->ops->dsp_black(dev_drv, 1);
if (dev_drv->ops->set_screen_scaler)
dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 0);
}
if (rk_fb->disp_mode == ONE_DUAL) {
dev_drv->cur_screen = dev_drv->screen0;
dev_drv->ops->load_screen(dev_drv, 1);
- if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
- dev_drv->trsm_ops->enable();
+
+ /* force modify dsp size */
+ info = rk_fb->fb[dev_drv->fb_index_base];
+ info->var.grayscale &= 0xff;
+ info->var.grayscale |=
+ (dev_drv->cur_screen->mode.xres << 8) +
+ (dev_drv->cur_screen->mode.yres << 20);
+ info->fbops->fb_set_par(info);
+ info->fbops->fb_pan_display(&info->var, info);
+
+ if (dev_drv->ops->dsp_black)
+ dev_drv->ops->dsp_black(dev_drv, 0);
} else if (rk_fb->num_lcdc > 1) {
/* If there is more than one lcdc device, we disable
the layer which attached to this device */
load_screen = 1;
}
info->var.activate |= FB_ACTIVATE_FORCE;
- if (rk_fb->disp_mode == DUAL)
+ if (rk_fb->disp_mode == DUAL) {
rk_fb_update_ext_info(info, pmy_info, 1);
+ } else if (rk_fb->disp_mode == ONE_DUAL) {
+ info->var.grayscale &= 0xff;
+ info->var.grayscale |=
+ (dev_drv->cur_screen->xsize << 8) +
+ (dev_drv->cur_screen->ysize << 20);
+ }
info->fbops->fb_set_par(info);
info->fbops->fb_pan_display(&info->var, info);
}
if (rk_fb->disp_mode == ONE_DUAL) {
if (dev_drv->ops->set_screen_scaler)
dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 1);
- if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable)
- dev_drv->trsm_ops->enable();
+ if (dev_drv->ops->dsp_black)
+ dev_drv->ops->dsp_black(dev_drv, 0);
}
return 0;
}
int (*cfg_done) (struct rk_lcdc_driver *dev_drv);
int (*set_overscan) (struct rk_lcdc_driver *dev_drv,
struct overscan *overscan);
+ int (*dsp_black) (struct rk_lcdc_driver *dev_drv, int enable);
};
struct rk_fb_area_par {