Merge branch 'master' of https://gitlab.denx.de/u-boot/custodians/u-boot-imx
This commit is contained in:
@@ -69,6 +69,22 @@ config CLK_IMX8MP
|
||||
help
|
||||
This enables support clock driver for i.MX8MP platforms.
|
||||
|
||||
config SPL_CLK_IMXRT1020
|
||||
bool "SPL clock support for i.MXRT1020"
|
||||
depends on ARCH_IMXRT && SPL
|
||||
select SPL_CLK
|
||||
select SPL_CLK_CCF
|
||||
help
|
||||
This enables SPL DM/DTS support for clock driver in i.MXRT1020
|
||||
|
||||
config CLK_IMXRT1020
|
||||
bool "Clock support for i.MXRT1020"
|
||||
depends on ARCH_IMXRT
|
||||
select CLK
|
||||
select CLK_CCF
|
||||
help
|
||||
This enables support clock driver for i.MXRT1020 platforms.
|
||||
|
||||
config SPL_CLK_IMXRT1050
|
||||
bool "SPL clock support for i.MXRT1050"
|
||||
depends on ARCH_IMXRT && SPL
|
||||
|
||||
@@ -17,4 +17,5 @@ obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MN) += clk-imx8mn.o clk-pll14xx.o \
|
||||
obj-$(CONFIG_$(SPL_TPL_)CLK_IMX8MP) += clk-imx8mp.o clk-pll14xx.o \
|
||||
clk-composite-8m.o
|
||||
|
||||
obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1020) += clk-imxrt1020.o
|
||||
obj-$(CONFIG_$(SPL_TPL_)CLK_IMXRT1050) += clk-imxrt1050.o
|
||||
|
||||
227
drivers/clk/imx/clk-imxrt1020.c
Normal file
227
drivers/clk/imx/clk-imxrt1020.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright(C) 2020
|
||||
* Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <clk-uclass.h>
|
||||
#include <dm.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/imx-regs.h>
|
||||
#include <dt-bindings/clock/imxrt1020-clock.h>
|
||||
|
||||
#include "clk.h"
|
||||
|
||||
static ulong imxrt1020_clk_get_rate(struct clk *clk)
|
||||
{
|
||||
struct clk *c;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu)\n", __func__, clk->id);
|
||||
|
||||
ret = clk_get_by_id(clk->id, &c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return clk_get_rate(c);
|
||||
}
|
||||
|
||||
static ulong imxrt1020_clk_set_rate(struct clk *clk, unsigned long rate)
|
||||
{
|
||||
struct clk *c;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
|
||||
|
||||
ret = clk_get_by_id(clk->id, &c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return clk_set_rate(c, rate);
|
||||
}
|
||||
|
||||
static int __imxrt1020_clk_enable(struct clk *clk, bool enable)
|
||||
{
|
||||
struct clk *c;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu) en: %d\n", __func__, clk->id, enable);
|
||||
|
||||
ret = clk_get_by_id(clk->id, &c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (enable)
|
||||
ret = clk_enable(c);
|
||||
else
|
||||
ret = clk_disable(c);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imxrt1020_clk_disable(struct clk *clk)
|
||||
{
|
||||
return __imxrt1020_clk_enable(clk, 0);
|
||||
}
|
||||
|
||||
static int imxrt1020_clk_enable(struct clk *clk)
|
||||
{
|
||||
return __imxrt1020_clk_enable(clk, 1);
|
||||
}
|
||||
|
||||
static struct clk_ops imxrt1020_clk_ops = {
|
||||
.set_rate = imxrt1020_clk_set_rate,
|
||||
.get_rate = imxrt1020_clk_get_rate,
|
||||
.enable = imxrt1020_clk_enable,
|
||||
.disable = imxrt1020_clk_disable,
|
||||
};
|
||||
|
||||
static const char * const pll2_bypass_sels[] = {"pll2_sys", "osc", };
|
||||
static const char * const pll3_bypass_sels[] = {"pll3_usb_otg", "osc", };
|
||||
|
||||
static const char *const pre_periph_sels[] = { "pll2_sys", "pll2_pfd3_297m", "pll3_pfd3_454_74m", "arm_podf", };
|
||||
static const char *const periph_sels[] = { "pre_periph_sel", "todo", };
|
||||
static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *const lpuart_sels[] = { "pll3_80m", "osc", };
|
||||
static const char *const semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", };
|
||||
static const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", };
|
||||
|
||||
static int imxrt1020_clk_probe(struct udevice *dev)
|
||||
{
|
||||
void *base;
|
||||
|
||||
/* Anatop clocks */
|
||||
base = (void *)ANATOP_BASE_ADDR;
|
||||
|
||||
clk_dm(IMXRT1020_CLK_PLL2_SYS,
|
||||
imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "osc",
|
||||
base + 0x30, 0x1));
|
||||
clk_dm(IMXRT1020_CLK_PLL3_USB_OTG,
|
||||
imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg", "osc",
|
||||
base + 0x10, 0x1));
|
||||
|
||||
/* PLL bypass out */
|
||||
clk_dm(IMXRT1020_CLK_PLL2_BYPASS,
|
||||
imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1,
|
||||
pll2_bypass_sels,
|
||||
ARRAY_SIZE(pll2_bypass_sels),
|
||||
CLK_SET_RATE_PARENT));
|
||||
clk_dm(IMXRT1020_CLK_PLL3_BYPASS,
|
||||
imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1,
|
||||
pll3_bypass_sels,
|
||||
ARRAY_SIZE(pll3_bypass_sels),
|
||||
CLK_SET_RATE_PARENT));
|
||||
|
||||
clk_dm(IMXRT1020_CLK_PLL3_80M,
|
||||
imx_clk_fixed_factor("pll3_80m", "pll3_usb_otg", 1, 6));
|
||||
|
||||
clk_dm(IMXRT1020_CLK_PLL2_PFD0_352M,
|
||||
imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + 0x100, 0));
|
||||
clk_dm(IMXRT1020_CLK_PLL2_PFD1_594M,
|
||||
imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + 0x100, 1));
|
||||
clk_dm(IMXRT1020_CLK_PLL2_PFD2_396M,
|
||||
imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + 0x100, 2));
|
||||
clk_dm(IMXRT1020_CLK_PLL2_PFD3_297M,
|
||||
imx_clk_pfd("pll2_pfd3_297m", "pll2_sys", base + 0x100, 3));
|
||||
clk_dm(IMXRT1020_CLK_PLL3_PFD1_664_62M,
|
||||
imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base + 0xf0, 1));
|
||||
clk_dm(IMXRT1020_CLK_PLL3_PFD3_454_74M,
|
||||
imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base + 0xf0, 3));
|
||||
|
||||
/* CCM clocks */
|
||||
base = dev_read_addr_ptr(dev);
|
||||
if (base == (void *)FDT_ADDR_T_NONE)
|
||||
return -EINVAL;
|
||||
|
||||
clk_dm(IMXRT1020_CLK_PRE_PERIPH_SEL,
|
||||
imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2,
|
||||
pre_periph_sels, ARRAY_SIZE(pre_periph_sels)));
|
||||
clk_dm(IMXRT1020_CLK_PERIPH_SEL,
|
||||
imx_clk_mux("periph_sel", base + 0x14, 25, 1,
|
||||
periph_sels, ARRAY_SIZE(periph_sels)));
|
||||
clk_dm(IMXRT1020_CLK_USDHC1_SEL,
|
||||
imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
|
||||
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
|
||||
clk_dm(IMXRT1020_CLK_USDHC2_SEL,
|
||||
imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
|
||||
usdhc_sels, ARRAY_SIZE(usdhc_sels)));
|
||||
clk_dm(IMXRT1020_CLK_LPUART_SEL,
|
||||
imx_clk_mux("lpuart_sel", base + 0x24, 6, 1,
|
||||
lpuart_sels, ARRAY_SIZE(lpuart_sels)));
|
||||
clk_dm(IMXRT1020_CLK_SEMC_ALT_SEL,
|
||||
imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1,
|
||||
semc_alt_sels, ARRAY_SIZE(semc_alt_sels)));
|
||||
clk_dm(IMXRT1020_CLK_SEMC_SEL,
|
||||
imx_clk_mux("semc_sel", base + 0x14, 6, 1,
|
||||
semc_sels, ARRAY_SIZE(semc_sels)));
|
||||
|
||||
clk_dm(IMXRT1020_CLK_AHB_PODF,
|
||||
imx_clk_divider("ahb_podf", "periph_sel",
|
||||
base + 0x14, 10, 3));
|
||||
clk_dm(IMXRT1020_CLK_USDHC1_PODF,
|
||||
imx_clk_divider("usdhc1_podf", "usdhc1_sel",
|
||||
base + 0x24, 11, 3));
|
||||
clk_dm(IMXRT1020_CLK_USDHC2_PODF,
|
||||
imx_clk_divider("usdhc2_podf", "usdhc2_sel",
|
||||
base + 0x24, 16, 3));
|
||||
clk_dm(IMXRT1020_CLK_LPUART_PODF,
|
||||
imx_clk_divider("lpuart_podf", "lpuart_sel",
|
||||
base + 0x24, 0, 6));
|
||||
clk_dm(IMXRT1020_CLK_SEMC_PODF,
|
||||
imx_clk_divider("semc_podf", "semc_sel",
|
||||
base + 0x14, 16, 3));
|
||||
|
||||
clk_dm(IMXRT1020_CLK_USDHC1,
|
||||
imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
|
||||
clk_dm(IMXRT1020_CLK_USDHC2,
|
||||
imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
|
||||
clk_dm(IMXRT1020_CLK_LPUART1,
|
||||
imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, 24));
|
||||
clk_dm(IMXRT1020_CLK_SEMC,
|
||||
imx_clk_gate2("semc", "semc_podf", base + 0x74, 4));
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
struct clk *clk, *clk1;
|
||||
|
||||
clk_get_by_id(IMXRT1020_CLK_SEMC_SEL, &clk1);
|
||||
clk_get_by_id(IMXRT1020_CLK_SEMC_ALT_SEL, &clk);
|
||||
clk_set_parent(clk1, clk);
|
||||
|
||||
/* Configure PLL3_USB_OTG to 480MHz */
|
||||
clk_get_by_id(IMXRT1020_CLK_PLL3_USB_OTG, &clk);
|
||||
clk_enable(clk);
|
||||
clk_set_rate(clk, 480000000UL);
|
||||
|
||||
clk_get_by_id(IMXRT1020_CLK_PLL3_BYPASS, &clk1);
|
||||
clk_set_parent(clk1, clk);
|
||||
|
||||
clk_get_by_id(IMXRT1020_CLK_PLL2_PFD3_297M, &clk);
|
||||
clk_set_rate(clk, 297000000UL);
|
||||
|
||||
clk_get_by_id(IMXRT1020_CLK_PLL2_SYS, &clk);
|
||||
clk_enable(clk);
|
||||
clk_set_rate(clk, 528000000UL);
|
||||
|
||||
clk_get_by_id(IMXRT1020_CLK_PLL2_BYPASS, &clk1);
|
||||
clk_set_parent(clk1, clk);
|
||||
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id imxrt1020_clk_ids[] = {
|
||||
{ .compatible = "fsl,imxrt1020-ccm" },
|
||||
{ },
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(imxrt1020_clk) = {
|
||||
.name = "clk_imxrt1020",
|
||||
.id = UCLASS_CLK,
|
||||
.of_match = imxrt1020_clk_ids,
|
||||
.ops = &imxrt1020_clk_ops,
|
||||
.probe = imxrt1020_clk_probe,
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -71,11 +71,30 @@ static int imxrt1050_clk_enable(struct clk *clk)
|
||||
return __imxrt1050_clk_enable(clk, 1);
|
||||
}
|
||||
|
||||
static int imxrt1050_clk_set_parent(struct clk *clk, struct clk *parent)
|
||||
{
|
||||
struct clk *c, *cp;
|
||||
int ret;
|
||||
|
||||
debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id);
|
||||
|
||||
ret = clk_get_by_id(clk->id, &c);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = clk_get_by_id(parent->id, &cp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return clk_set_parent(c, cp);
|
||||
}
|
||||
|
||||
static struct clk_ops imxrt1050_clk_ops = {
|
||||
.set_rate = imxrt1050_clk_set_rate,
|
||||
.get_rate = imxrt1050_clk_get_rate,
|
||||
.enable = imxrt1050_clk_enable,
|
||||
.disable = imxrt1050_clk_disable,
|
||||
.set_parent = imxrt1050_clk_set_parent,
|
||||
};
|
||||
|
||||
static const char * const pll_ref_sels[] = {"osc", "dummy", };
|
||||
@@ -90,7 +109,7 @@ static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
|
||||
static const char *const lpuart_sels[] = { "pll3_80m", "osc", };
|
||||
static const char *const semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", };
|
||||
static const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", };
|
||||
static const char *const lcdif_sels[] = { "pll2_sys", "pll3_pfd3_454_74m", "pll5_video:", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_664_62m"};
|
||||
static const char *const lcdif_sels[] = { "pll2_sys", "pll3_pfd3_454_74m", "pll5_video", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_664_62m"};
|
||||
|
||||
static int imxrt1050_clk_probe(struct udevice *dev)
|
||||
{
|
||||
@@ -238,9 +257,9 @@ static int imxrt1050_clk_probe(struct udevice *dev)
|
||||
clk_dm(IMXRT1050_CLK_LCDIF,
|
||||
imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, 28));
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
struct clk *clk, *clk1;
|
||||
|
||||
#ifdef CONFIG_SPL_BUILD
|
||||
/* bypass pll1 before setting its rate */
|
||||
clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk);
|
||||
clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1);
|
||||
@@ -271,7 +290,14 @@ static int imxrt1050_clk_probe(struct udevice *dev)
|
||||
|
||||
clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1);
|
||||
clk_set_parent(clk1, clk);
|
||||
#else
|
||||
/* Set PLL5 for LCDIF to its default 650Mhz */
|
||||
clk_get_by_id(IMXRT1050_CLK_PLL5_VIDEO, &clk);
|
||||
clk_enable(clk);
|
||||
clk_set_rate(clk, 650000000UL);
|
||||
|
||||
clk_get_by_id(IMXRT1050_CLK_PLL5_BYPASS, &clk1);
|
||||
clk_set_parent(clk1, clk);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#define PLL_DENOM_OFFSET 0x20
|
||||
|
||||
#define BM_PLL_POWER (0x1 << 12)
|
||||
#define BM_PLL_ENABLE (0x1 << 13)
|
||||
#define BM_PLL_LOCK (0x1 << 31)
|
||||
|
||||
struct clk_pllv3 {
|
||||
@@ -32,6 +33,7 @@ struct clk_pllv3 {
|
||||
void __iomem *base;
|
||||
u32 power_bit;
|
||||
bool powerup_set;
|
||||
u32 enable_bit;
|
||||
u32 div_mask;
|
||||
u32 div_shift;
|
||||
};
|
||||
@@ -83,6 +85,9 @@ static int clk_pllv3_generic_enable(struct clk *clk)
|
||||
val |= pll->power_bit;
|
||||
else
|
||||
val &= ~pll->power_bit;
|
||||
|
||||
val |= pll->enable_bit;
|
||||
|
||||
writel(val, pll->base);
|
||||
|
||||
return 0;
|
||||
@@ -98,6 +103,9 @@ static int clk_pllv3_generic_disable(struct clk *clk)
|
||||
val &= ~pll->power_bit;
|
||||
else
|
||||
val |= pll->power_bit;
|
||||
|
||||
val &= ~pll->enable_bit;
|
||||
|
||||
writel(val, pll->base);
|
||||
|
||||
return 0;
|
||||
@@ -238,6 +246,7 @@ struct clk *imx_clk_pllv3(enum imx_pllv3_type type, const char *name,
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pll->power_bit = BM_PLL_POWER;
|
||||
pll->enable_bit = BM_PLL_ENABLE;
|
||||
|
||||
switch (type) {
|
||||
case IMX_PLLV3_GENERIC:
|
||||
|
||||
@@ -41,7 +41,7 @@ static int pfuze100_write(struct udevice *dev, uint reg, const uint8_t *buff,
|
||||
static int pfuze100_read(struct udevice *dev, uint reg, uint8_t *buff, int len)
|
||||
{
|
||||
if (dm_i2c_read(dev, reg, buff, len)) {
|
||||
pr_err("read error from device: %p register: %#x!\n", dev, reg);
|
||||
debug("read error from device: %p register: %#x!\n", dev, reg);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2011-2013 Marek Vasut <marex@denx.de>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <env.h>
|
||||
#include <dm/device_compat.h>
|
||||
@@ -52,14 +53,34 @@ __weak void mxsfb_system_setup(void)
|
||||
* le:89,ri:164,up:23,lo:10,hs:10,vs:10,sync:0,vmode:0
|
||||
*/
|
||||
|
||||
static void mxs_lcd_init(u32 fb_addr, struct ctfb_res_modes *mode, int bpp)
|
||||
static void mxs_lcd_init(struct udevice *dev, u32 fb_addr,
|
||||
struct display_timing *timings, int bpp)
|
||||
{
|
||||
struct mxs_lcdif_regs *regs = (struct mxs_lcdif_regs *)MXS_LCDIF_BASE;
|
||||
const enum display_flags flags = timings->flags;
|
||||
uint32_t word_len = 0, bus_width = 0;
|
||||
uint8_t valid_data = 0;
|
||||
uint32_t vdctrl0;
|
||||
|
||||
#if CONFIG_IS_ENABLED(CLK)
|
||||
struct clk per_clk;
|
||||
int ret;
|
||||
|
||||
ret = clk_get_by_name(dev, "per", &per_clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Failed to get mxs clk: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = clk_set_rate(&per_clk, timings->pixelclock.typ);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to set mxs clk: %d\n", ret);
|
||||
return;
|
||||
}
|
||||
#else
|
||||
/* Kick in the LCDIF clock */
|
||||
mxs_set_lcdclk(MXS_LCDIF_BASE, PS2KHZ(mode->pixclock));
|
||||
mxs_set_lcdclk(MXS_LCDIF_BASE, timings->pixelclock.typ / 1000);
|
||||
#endif
|
||||
|
||||
/* Restart the LCDIF block */
|
||||
mxs_reset_block(®s->hw_lcdif_ctrl_reg);
|
||||
@@ -96,25 +117,36 @@ static void mxs_lcd_init(u32 fb_addr, struct ctfb_res_modes *mode, int bpp)
|
||||
|
||||
mxsfb_system_setup();
|
||||
|
||||
writel((mode->yres << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) | mode->xres,
|
||||
®s->hw_lcdif_transfer_count);
|
||||
writel((timings->vactive.typ << LCDIF_TRANSFER_COUNT_V_COUNT_OFFSET) |
|
||||
timings->hactive.typ, ®s->hw_lcdif_transfer_count);
|
||||
|
||||
writel(LCDIF_VDCTRL0_ENABLE_PRESENT | LCDIF_VDCTRL0_ENABLE_POL |
|
||||
LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
|
||||
LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
|
||||
mode->vsync_len, ®s->hw_lcdif_vdctrl0);
|
||||
writel(mode->upper_margin + mode->lower_margin +
|
||||
mode->vsync_len + mode->yres,
|
||||
vdctrl0 = LCDIF_VDCTRL0_ENABLE_PRESENT | LCDIF_VDCTRL0_ENABLE_POL |
|
||||
LCDIF_VDCTRL0_VSYNC_PERIOD_UNIT |
|
||||
LCDIF_VDCTRL0_VSYNC_PULSE_WIDTH_UNIT |
|
||||
timings->vsync_len.typ;
|
||||
|
||||
if(flags & DISPLAY_FLAGS_HSYNC_HIGH)
|
||||
vdctrl0 |= LCDIF_VDCTRL0_HSYNC_POL;
|
||||
if(flags & DISPLAY_FLAGS_VSYNC_HIGH)
|
||||
vdctrl0 |= LCDIF_VDCTRL0_VSYNC_POL;
|
||||
if(flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
|
||||
vdctrl0 |= LCDIF_VDCTRL0_DOTCLK_POL;
|
||||
if(flags & DISPLAY_FLAGS_DE_HIGH)
|
||||
vdctrl0 |= LCDIF_VDCTRL0_ENABLE_POL;
|
||||
|
||||
writel(vdctrl0, ®s->hw_lcdif_vdctrl0);
|
||||
writel(timings->vback_porch.typ + timings->vfront_porch.typ +
|
||||
timings->vsync_len.typ + timings->vactive.typ,
|
||||
®s->hw_lcdif_vdctrl1);
|
||||
writel((mode->hsync_len << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_OFFSET) |
|
||||
(mode->left_margin + mode->right_margin +
|
||||
mode->hsync_len + mode->xres),
|
||||
writel((timings->hsync_len.typ << LCDIF_VDCTRL2_HSYNC_PULSE_WIDTH_OFFSET) |
|
||||
(timings->hback_porch.typ + timings->hfront_porch.typ +
|
||||
timings->hsync_len.typ + timings->hactive.typ),
|
||||
®s->hw_lcdif_vdctrl2);
|
||||
writel(((mode->left_margin + mode->hsync_len) <<
|
||||
writel(((timings->hback_porch.typ + timings->hsync_len.typ) <<
|
||||
LCDIF_VDCTRL3_HORIZONTAL_WAIT_CNT_OFFSET) |
|
||||
(mode->upper_margin + mode->vsync_len),
|
||||
(timings->vback_porch.typ + timings->vsync_len.typ),
|
||||
®s->hw_lcdif_vdctrl3);
|
||||
writel((0 << LCDIF_VDCTRL4_DOTCLK_DLY_SEL_OFFSET) | mode->xres,
|
||||
writel((0 << LCDIF_VDCTRL4_DOTCLK_DLY_SEL_OFFSET) | timings->hactive.typ,
|
||||
®s->hw_lcdif_vdctrl4);
|
||||
|
||||
writel(fb_addr, ®s->hw_lcdif_cur_buf);
|
||||
@@ -135,10 +167,11 @@ static void mxs_lcd_init(u32 fb_addr, struct ctfb_res_modes *mode, int bpp)
|
||||
writel(LCDIF_CTRL_RUN, ®s->hw_lcdif_ctrl_set);
|
||||
}
|
||||
|
||||
static int mxs_probe_common(struct ctfb_res_modes *mode, int bpp, u32 fb)
|
||||
static int mxs_probe_common(struct udevice *dev, struct display_timing *timings,
|
||||
int bpp, u32 fb)
|
||||
{
|
||||
/* Start framebuffer */
|
||||
mxs_lcd_init(fb, mode, bpp);
|
||||
mxs_lcd_init(dev, fb, timings, bpp);
|
||||
|
||||
#ifdef CONFIG_VIDEO_MXS_MODE_SYSTEM
|
||||
/*
|
||||
@@ -204,6 +237,7 @@ void *video_hw_init(void)
|
||||
char *penv;
|
||||
void *fb = NULL;
|
||||
struct ctfb_res_modes mode;
|
||||
struct display_timing timings;
|
||||
|
||||
puts("Video: ");
|
||||
|
||||
@@ -260,7 +294,9 @@ void *video_hw_init(void)
|
||||
|
||||
printf("%s\n", panel.modeIdent);
|
||||
|
||||
ret = mxs_probe_common(&mode, bpp, (u32)fb);
|
||||
video_ctfb_mode_to_display_timing(&mode, &timings);
|
||||
|
||||
ret = mxs_probe_common(NULL, &timings, bpp, (u32)fb);
|
||||
if (ret)
|
||||
goto dealloc_fb;
|
||||
|
||||
@@ -314,7 +350,6 @@ static int mxs_video_probe(struct udevice *dev)
|
||||
struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
|
||||
struct video_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
struct ctfb_res_modes mode;
|
||||
struct display_timing timings;
|
||||
u32 bpp = 0;
|
||||
u32 fb_start, fb_end;
|
||||
@@ -327,17 +362,7 @@ static int mxs_video_probe(struct udevice *dev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mode.xres = timings.hactive.typ;
|
||||
mode.yres = timings.vactive.typ;
|
||||
mode.left_margin = timings.hback_porch.typ;
|
||||
mode.right_margin = timings.hfront_porch.typ;
|
||||
mode.upper_margin = timings.vback_porch.typ;
|
||||
mode.lower_margin = timings.vfront_porch.typ;
|
||||
mode.hsync_len = timings.hsync_len.typ;
|
||||
mode.vsync_len = timings.vsync_len.typ;
|
||||
mode.pixclock = HZ2PS(timings.pixelclock.typ);
|
||||
|
||||
ret = mxs_probe_common(&mode, bpp, plat->base);
|
||||
ret = mxs_probe_common(dev, &timings, bpp, plat->base);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -358,8 +383,8 @@ static int mxs_video_probe(struct udevice *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
uc_priv->xsize = mode.xres;
|
||||
uc_priv->ysize = mode.yres;
|
||||
uc_priv->xsize = timings.hactive.typ;
|
||||
uc_priv->ysize = timings.vactive.typ;
|
||||
|
||||
/* Enable dcache for the frame buffer */
|
||||
fb_start = plat->base & ~(MMU_SECTION_SIZE - 1);
|
||||
@@ -420,6 +445,7 @@ static const struct udevice_id mxs_video_ids[] = {
|
||||
{ .compatible = "fsl,imx23-lcdif" },
|
||||
{ .compatible = "fsl,imx28-lcdif" },
|
||||
{ .compatible = "fsl,imx7ulp-lcdif" },
|
||||
{ .compatible = "fsl,imxrt-lcdif" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
|
||||
@@ -615,35 +615,6 @@ static void sunxi_lcdc_backlight_enable(void)
|
||||
gpio_direction_output(pin, PWM_ON);
|
||||
}
|
||||
|
||||
static void sunxi_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
|
||||
struct display_timing *timing)
|
||||
{
|
||||
timing->pixelclock.typ = mode->pixclock_khz * 1000;
|
||||
|
||||
timing->hactive.typ = mode->xres;
|
||||
timing->hfront_porch.typ = mode->right_margin;
|
||||
timing->hback_porch.typ = mode->left_margin;
|
||||
timing->hsync_len.typ = mode->hsync_len;
|
||||
|
||||
timing->vactive.typ = mode->yres;
|
||||
timing->vfront_porch.typ = mode->lower_margin;
|
||||
timing->vback_porch.typ = mode->upper_margin;
|
||||
timing->vsync_len.typ = mode->vsync_len;
|
||||
|
||||
timing->flags = 0;
|
||||
|
||||
if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
|
||||
timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
|
||||
else
|
||||
timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
|
||||
if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
|
||||
timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
|
||||
else
|
||||
timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
|
||||
if (mode->vmode == FB_VMODE_INTERLACED)
|
||||
timing->flags |= DISPLAY_FLAGS_INTERLACED;
|
||||
}
|
||||
|
||||
static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
|
||||
bool for_ext_vga_dac)
|
||||
{
|
||||
@@ -673,7 +644,7 @@ static void sunxi_lcdc_tcon0_mode_set(const struct ctfb_res_modes *mode,
|
||||
lcdc_pll_set(ccm, 0, mode->pixclock_khz, &clk_div, &clk_double,
|
||||
sunxi_is_composite());
|
||||
|
||||
sunxi_ctfb_mode_to_display_timing(mode, &timing);
|
||||
video_ctfb_mode_to_display_timing(mode, &timing);
|
||||
lcdc_tcon0_mode_set(lcdc, &timing, clk_div, for_ext_vga_dac,
|
||||
sunxi_display.depth, CONFIG_VIDEO_LCD_DCLK_PHASE);
|
||||
}
|
||||
@@ -689,7 +660,7 @@ static void sunxi_lcdc_tcon1_mode_set(const struct ctfb_res_modes *mode,
|
||||
(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
|
||||
struct display_timing timing;
|
||||
|
||||
sunxi_ctfb_mode_to_display_timing(mode, &timing);
|
||||
video_ctfb_mode_to_display_timing(mode, &timing);
|
||||
lcdc_tcon1_mode_set(lcdc, &timing, use_portd_hvsync,
|
||||
sunxi_is_composite());
|
||||
|
||||
|
||||
@@ -444,3 +444,32 @@ int video_edid_dtd_to_ctfb_res_modes(struct edid_detailed_timing *t,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void video_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
|
||||
struct display_timing *timing)
|
||||
{
|
||||
timing->pixelclock.typ = mode->pixclock_khz * 1000;
|
||||
|
||||
timing->hactive.typ = mode->xres;
|
||||
timing->hfront_porch.typ = mode->right_margin;
|
||||
timing->hback_porch.typ = mode->left_margin;
|
||||
timing->hsync_len.typ = mode->hsync_len;
|
||||
|
||||
timing->vactive.typ = mode->yres;
|
||||
timing->vfront_porch.typ = mode->lower_margin;
|
||||
timing->vback_porch.typ = mode->upper_margin;
|
||||
timing->vsync_len.typ = mode->vsync_len;
|
||||
|
||||
timing->flags = 0;
|
||||
|
||||
if (mode->sync & FB_SYNC_HOR_HIGH_ACT)
|
||||
timing->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
|
||||
else
|
||||
timing->flags |= DISPLAY_FLAGS_HSYNC_LOW;
|
||||
if (mode->sync & FB_SYNC_VERT_HIGH_ACT)
|
||||
timing->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
|
||||
else
|
||||
timing->flags |= DISPLAY_FLAGS_VSYNC_LOW;
|
||||
if (mode->vmode == FB_VMODE_INTERLACED)
|
||||
timing->flags |= DISPLAY_FLAGS_INTERLACED;
|
||||
}
|
||||
|
||||
@@ -92,3 +92,14 @@ int video_get_option_int(const char *options, const char *name, int def);
|
||||
|
||||
int video_edid_dtd_to_ctfb_res_modes(struct edid_detailed_timing *t,
|
||||
struct ctfb_res_modes *mode);
|
||||
/**
|
||||
* video_ctfb_mode_to_display_timing() - Convert a ctfb(Cathode Tube Frame
|
||||
* Buffer)_res_modes struct to a
|
||||
* display_timing struct.
|
||||
*
|
||||
* @mode: Input ctfb_res_modes structure pointer to be converted
|
||||
* from
|
||||
* @timing: Output display_timing structure pointer to be converted to
|
||||
*/
|
||||
void video_ctfb_mode_to_display_timing(const struct ctfb_res_modes *mode,
|
||||
struct display_timing *timing);
|
||||
|
||||
Reference in New Issue
Block a user