X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fgpu%2Fdrm%2Frockchip%2Fdw-mipi-dsi.c;h=890fd83b7a08f91c4327fec7d11279cce62ced2d;hb=6d82179b6f6109ca609b49c470bb9c585ca697f0;hp=d6b3e70eecf50dfdae956662833e5c3b01314e56;hpb=e22192940c76aec82efe10edf3d289eafcbf99cc;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c index d6b3e70eecf5..890fd83b7a08 100644 --- a/drivers/gpu/drm/rockchip/dw-mipi-dsi.c +++ b/drivers/gpu/drm/rockchip/dw-mipi-dsi.c @@ -94,9 +94,12 @@ #define ENABLE_CMD_MODE BIT(0) #define DSI_VID_MODE_CFG 0x38 +#define VPG_EN BIT(16) #define FRAME_BTA_ACK BIT(14) -#define ENABLE_LOW_POWER (0x3f << 8) -#define ENABLE_LOW_POWER_MASK (0x3f << 8) +#define LP_HFP_EN BIT(13) +#define LP_HBP_EN BIT(12) +#define ENABLE_LOW_POWER (0xf << 8) +#define ENABLE_LOW_POWER_MASK (0xf << 8) #define VID_MODE_TYPE_BURST_SYNC_PULSES 0x0 #define VID_MODE_TYPE_BURST_SYNC_EVENTS 0x1 #define VID_MODE_TYPE_BURST 0x2 @@ -512,7 +515,6 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi) dsi_write(dsi, DSI_PHY_RSTZ, PHY_ENFORCEPLL | PHY_ENABLECLK | PHY_UNRSTZ | PHY_UNSHUTDOWNZ); - ret = readx_poll_timeout(readl, dsi->base + DSI_PHY_STATUS, val, val & LOCK, 1000, PHY_STATUS_TIMEOUT_US); if (ret < 0) { @@ -534,31 +536,50 @@ phy_init_end: return ret; } -static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) +static int rockchip_dsi_calc_bandwidth(struct dw_mipi_dsi *dsi) { - unsigned int i, pre; - unsigned long mpclk, pllref, tmp; - unsigned int m = 1, n = 1, target_mbps = 1000; - unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps; int bpp; + unsigned long mpclk, tmp; + unsigned int target_mbps = 1000; + unsigned int value; + struct device_node *np = dsi->dev->of_node; + unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps; + int lanes; + + /* optional override of the desired bandwidth */ + if (!of_property_read_u32(np, "rockchip,lane-rate", &value)) + return value; bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); if (bpp < 0) { dev_err(dsi->dev, "failed to get bpp for pixel format %d\n", dsi->format); - return bpp; + bpp = 24; } + lanes = dsi->lanes; + mpclk = DIV_ROUND_UP(dsi->mode.clock, MSEC_PER_SEC); if (mpclk) { /* take 1 / 0.9, since mbps must big than bandwidth of RGB */ - tmp = mpclk * (bpp / dsi->lanes) * 10 / 9; + tmp = mpclk * (bpp / lanes) * 10 / 9; if (tmp < max_mbps) target_mbps = tmp; else dev_err(dsi->dev, "DPHY clock frequency is out of range\n"); } + return target_mbps; +} + +static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) +{ + unsigned int i, pre; + unsigned long pllref, tmp; + unsigned int m = 1, n = 1, target_mbps; + + target_mbps = rockchip_dsi_calc_bandwidth(dsi); + pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); tmp = pllref; @@ -624,10 +645,13 @@ static int dw_mipi_dsi_host_detach(struct mipi_dsi_host *host, static void rockchip_set_transfer_mode(struct dw_mipi_dsi *dsi, int flags) { - if (flags & MIPI_DSI_MSG_USE_LPM) + if (flags & MIPI_DSI_MSG_USE_LPM) { dsi_write(dsi, DSI_CMD_MODE_CFG, CMD_MODE_ALL_LP); - else + dsi_write(dsi, DSI_LPCLK_CTRL, 0); + } else { dsi_write(dsi, DSI_CMD_MODE_CFG, 0); + dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); + } } static ssize_t dw_mipi_dsi_host_transfer(struct mipi_dsi_host *host, @@ -702,7 +726,14 @@ static void dw_mipi_dsi_video_mode_config(struct dw_mipi_dsi *dsi) { u32 val; - val = VID_MODE_TYPE_BURST | ENABLE_LOW_POWER; + val = LP_HFP_EN | ENABLE_LOW_POWER; + + if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST) + val |= VID_MODE_TYPE_BURST; + else if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) + val |= VID_MODE_TYPE_BURST_SYNC_PULSES; + else + val |= VID_MODE_TYPE_BURST_SYNC_EVENTS; dsi_write(dsi, DSI_VID_MODE_CFG, val); } @@ -723,7 +754,6 @@ static void dw_mipi_dsi_init(struct dw_mipi_dsi *dsi) | PHY_RSTZ | PHY_SHUTDOWNZ); dsi_write(dsi, DSI_CLKMGR_CFG, TO_CLK_DIVIDSION(10) | TX_ESC_CLK_DIVIDSION(7)); - dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); } static void dw_mipi_dsi_dpi_config(struct dw_mipi_dsi *dsi, @@ -779,16 +809,16 @@ static void dw_mipi_dsi_command_mode_config(struct dw_mipi_dsi *dsi) static u32 dw_mipi_dsi_get_hcomponent_lbcc(struct dw_mipi_dsi *dsi, u32 hcomponent) { - u32 frac, lbcc; + u32 lbcc; lbcc = hcomponent * dsi->lane_mbps * MSEC_PER_SEC / 8; - frac = lbcc % dsi->mode.clock; - lbcc = lbcc / dsi->mode.clock; - if (frac) - lbcc++; + if (dsi->mode.clock == 0) { + dev_err(dsi->dev, "dsi mode clock is 0!\n"); + return 0; + } - return lbcc; + return DIV_ROUND_CLOSEST_ULL(lbcc, dsi->mode.clock); } static void dw_mipi_dsi_line_timer_config(struct dw_mipi_dsi *dsi) @@ -927,6 +957,11 @@ static void rockchip_dsi_pre_init(struct dw_mipi_dsi *dsi) return; } + if (clk_prepare_enable(dsi->pllref_clk)) { + dev_err(dsi->dev, "Failed to enable pllref_clk\n"); + return; + } + pm_runtime_get_sync(dsi->dev); if (dsi->rst) { @@ -975,7 +1010,9 @@ static void rockchip_dsi_init(struct dw_mipi_dsi *dsi) static void rockchip_dsi_enable(struct dw_mipi_dsi *dsi) { + dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS); dw_mipi_dsi_set_mode(dsi, DSI_VIDEO_MODE); + clk_disable_unprepare(dsi->pllref_clk); clk_disable_unprepare(dsi->pclk); } @@ -1159,19 +1196,6 @@ static int dw_mipi_dsi_register(struct drm_device *drm, return 0; } -static int rockchip_mipi_parse_dt(struct dw_mipi_dsi *dsi) -{ - struct device_node *np = dsi->dev->of_node; - - dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); - if (IS_ERR(dsi->grf_regmap)) { - dev_err(dsi->dev, "Unable to get rockchip,grf\n"); - return PTR_ERR(dsi->grf_regmap); - } - - return 0; -} - static struct dw_mipi_dsi_plat_data rk3288_mipi_dsi_drv_data = { .dsi0_en_bit = RK3288_DSI0_SEL_VOP_LIT, .dsi1_en_bit = RK3288_DSI1_SEL_VOP_LIT, @@ -1226,33 +1250,67 @@ MODULE_DEVICE_TABLE(of, dw_mipi_dsi_dt_ids); static int dw_mipi_dsi_bind(struct device *dev, struct device *master, void *data) { - struct platform_device *pdev = to_platform_device(dev); struct drm_device *drm = data; struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); - struct resource *res; int ret; if (!dsi->panel) return -EPROBE_DEFER; - ret = rockchip_mipi_parse_dt(dsi); - if (ret) + ret = dw_mipi_dsi_register(drm, dsi); + if (ret) { + dev_err(dev, "Failed to register mipi_dsi: %d\n", ret); return ret; + } - dsi->phy = devm_phy_optional_get(dev, "mipi_dphy"); - if (IS_ERR(dsi->phy)) { - ret = PTR_ERR(dsi->phy); - dev_err(dev, "failed to get mipi dphy: %d\n", ret); - return ret; + dev_set_drvdata(dev, dsi); + + pm_runtime_enable(dev); + + return ret; +} + +static void dw_mipi_dsi_unbind(struct device *dev, struct device *master, + void *data) +{ + pm_runtime_disable(dev); +} + +static const struct component_ops dw_mipi_dsi_ops = { + .bind = dw_mipi_dsi_bind, + .unbind = dw_mipi_dsi_unbind, +}; + +static int rockchip_dsi_get_reset_handle(struct dw_mipi_dsi *dsi) +{ + struct device *dev = dsi->dev; + + dsi->rst = devm_reset_control_get_optional(dev, "apb"); + if (IS_ERR(dsi->rst)) { + dev_info(dev, "no reset control specified\n"); + dsi->rst = NULL; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; + return 0; +} - dsi->base = devm_ioremap_resource(dev, res); - if (IS_ERR(dsi->base)) - return PTR_ERR(dsi->base); +static int rockchip_dsi_grf_regmap(struct dw_mipi_dsi *dsi) +{ + struct device_node *np = dsi->dev->of_node; + + dsi->grf_regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(dsi->grf_regmap)) { + dev_err(dsi->dev, "Unable to get rockchip,grf\n"); + return PTR_ERR(dsi->grf_regmap); + } + + return 0; +} + +static int rockchip_dsi_clk_get(struct dw_mipi_dsi *dsi) +{ + struct device *dev = dsi->dev; + int ret; dsi->pclk = devm_clk_get(dev, "pclk"); if (IS_ERR(dsi->pclk)) { @@ -1261,62 +1319,52 @@ static int dw_mipi_dsi_bind(struct device *dev, struct device *master, return ret; } - /* optional */ dsi->pllref_clk = devm_clk_get(dev, "ref"); if (IS_ERR(dsi->pllref_clk)) { dev_info(dev, "No PHY reference clock specified\n"); dsi->pllref_clk = NULL; } - /* optional */ dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg"); if (IS_ERR(dsi->phy_cfg_clk)) { dev_info(dev, "No PHY APB clock specified\n"); dsi->phy_cfg_clk = NULL; } - ret = clk_prepare_enable(dsi->pllref_clk); - if (ret) { - dev_err(dev, "%s: Failed to enable pllref_clk\n", __func__); - return ret; - } + return 0; +} - dsi->rst = devm_reset_control_get_optional(dev, "apb"); - if (IS_ERR(dsi->rst)) { - dev_info(dev, "no reset control specified\n"); - dsi->rst = NULL; - } +static int rockchip_dsi_dphy_parse(struct dw_mipi_dsi *dsi) +{ + struct device *dev = dsi->dev; + int ret; - ret = dw_mipi_dsi_register(drm, dsi); - if (ret) { - dev_err(dev, "Failed to register mipi_dsi: %d\n", ret); - goto err_pllref; + dsi->phy = devm_phy_optional_get(dev, "mipi_dphy"); + if (IS_ERR(dsi->phy)) { + ret = PTR_ERR(dsi->phy); + dev_err(dev, "failed to get mipi dphy: %d\n", ret); + return ret; } - dev_set_drvdata(dev, dsi); - - pm_runtime_enable(dev); - return 0; - -err_pllref: - clk_disable_unprepare(dsi->pllref_clk); - return ret; } -static void dw_mipi_dsi_unbind(struct device *dev, struct device *master, - void *data) +static int rockchip_dsi_ioremap_resource(struct platform_device *pdev, + struct dw_mipi_dsi *dsi) { - struct dw_mipi_dsi *dsi = dev_get_drvdata(dev); + struct device *dev = &pdev->dev; + struct resource *res; - pm_runtime_disable(dev); - clk_disable_unprepare(dsi->pllref_clk); -} + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; -static const struct component_ops dw_mipi_dsi_ops = { - .bind = dw_mipi_dsi_bind, - .unbind = dw_mipi_dsi_unbind, -}; + dsi->base = devm_ioremap_resource(dev, res); + if (IS_ERR(dsi->base)) + return PTR_ERR(dsi->base); + + return 0; +} static int dw_mipi_dsi_probe(struct platform_device *pdev) { @@ -1333,6 +1381,13 @@ static int dw_mipi_dsi_probe(struct platform_device *pdev) dsi->dev = dev; dsi->pdata = pdata; + + rockchip_dsi_ioremap_resource(pdev, dsi); + rockchip_dsi_clk_get(dsi); + rockchip_dsi_dphy_parse(dsi); + rockchip_dsi_grf_regmap(dsi); + rockchip_dsi_get_reset_handle(dsi); + dsi->dsi_host.ops = &dw_mipi_dsi_host_ops; dsi->dsi_host.dev = &pdev->dev;