tegra124: add clock support code for graphics.
Add a graphics_clock function which is where we intend to do all clock
graphics init. This is modeled on how we are doing the UART clock; keep
it all in one place, not spread everywhere. Add sor_clock_{start,stop}
functions. We must start and stop the SOR clocks beore we mess with the
plldp.
BUG=None
TEST=This code builds and boots and shows graphics and depth charge screen.
BRANCH=None
Change-Id: Ida4a73f9020e5542f16d2ab0793fb2116156d562
Signed-off-by: Ronald G. Minnich <rminnich@google.com>
Reviewed-on: https://chromium-review.googlesource.com/175162
Reviewed-by: Hung-Te Lin <hungte@chromium.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Commit-Queue: Ronald Minnich <rminnich@chromium.org>
Tested-by: Ronald Minnich <rminnich@chromium.org>
This commit is contained in:
parent
df4c515d73
commit
b8eb6ab4cd
3 changed files with 63 additions and 25 deletions
|
|
@ -79,7 +79,8 @@ union __attribute__((transparent_union)) pll_fields {
|
|||
/* This table defines the frequency dividers for every PLL to turn the external
|
||||
* OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h.
|
||||
* All PLLs have three dividers (N, M and P), with the governing formula for
|
||||
* the output frequency being OUT = (IN / m) * N / (2^P). */
|
||||
* the output frequency being OUT = (IN / m) * N / (2^P).
|
||||
* Yes, it really is one equation with three unknowns ... */
|
||||
struct {
|
||||
int khz;
|
||||
struct pllcx_dividers pllx; /* target: 1900 MHz */
|
||||
|
|
@ -87,6 +88,7 @@ struct {
|
|||
struct pllcx_dividers pllc; /* target: 600 MHz */
|
||||
struct pllpad_dividers plld; /* target: 925 MHz */
|
||||
struct pllu_dividers pllu; /* target; 960 MHz */
|
||||
struct pllcx_dividers plldp; /* target; 270 MHz */
|
||||
} static const osc_table[16] = {
|
||||
[OSC_FREQ_OSC12]{
|
||||
.khz = 12000,
|
||||
|
|
@ -95,6 +97,7 @@ struct {
|
|||
.pllc = {.n = 50, .m = 1, .p = 0},
|
||||
.plld = {.n = 925, .m = 12, .p = 0, .cpcon = 12},
|
||||
.pllu = {.n = 80, .m = 1, .p = 0, .cpcon = 3},
|
||||
.plldp = {.n = 90, .m = 1, .p = 3}, /* 270 MHz */
|
||||
},
|
||||
[OSC_FREQ_OSC13]{
|
||||
.khz = 13000,
|
||||
|
|
@ -103,6 +106,7 @@ struct {
|
|||
.pllc = {.n = 231, .m = 5, .p = 0}, /* 600.6 MHz */
|
||||
.plld = {.n = 925, .m = 13, .p = 0, .cpcon = 12},
|
||||
.pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12},
|
||||
.plldp = {.n = 83, .m = 1, .p = 3}, /* 269.75 MHz */
|
||||
},
|
||||
[OSC_FREQ_OSC16P8]{
|
||||
.khz = 16800,
|
||||
|
|
@ -111,6 +115,7 @@ struct {
|
|||
.pllc = {.n = 250, .m = 7, .p = 0},
|
||||
.plld = {.n = 936, .m = 17, .p = 0, .cpcon = 12},/* 924.9 MHz */
|
||||
.pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 8},
|
||||
.plldp = {.n = 67, .m = 1, .p = 3}, /* 268 MHz */
|
||||
},
|
||||
[OSC_FREQ_OSC19P2]{
|
||||
.khz = 19200,
|
||||
|
|
@ -119,6 +124,7 @@ struct {
|
|||
.pllc = {.n = 125, .m = 4, .p = 0},
|
||||
.plld = {.n = 819, .m = 17, .p = 0, .cpcon = 12},/* 924.9 MHz */
|
||||
.pllu = {.n = 50, .m = 1, .p = 0, .cpcon = 2},
|
||||
.plldp = {.n = 57, .m = 1, .p = 3}, /* 270.75 MHz */
|
||||
},
|
||||
[OSC_FREQ_OSC26]{
|
||||
.khz = 26000,
|
||||
|
|
@ -127,6 +133,7 @@ struct {
|
|||
.pllc = {.n = 23, .m = 1, .p = 0}, /* 598 MHz */
|
||||
.plld = {.n = 925, .m = 26, .p = 0, .cpcon = 12},
|
||||
.pllu = {.n = 480, .m = 13, .p = 0, .cpcon = 8},
|
||||
.plldp = {.n = 41, .m = 1, .p = 3}, /* 266.50 MHz */
|
||||
},
|
||||
[OSC_FREQ_OSC38P4]{
|
||||
.khz = 38400,
|
||||
|
|
@ -135,6 +142,7 @@ struct {
|
|||
.pllc = {.n = 125, .m = 4, .p = 0},
|
||||
.plld = {.n = 819, .m = 17, .p = 0, .cpcon = 12},/* 924.9 MHz */
|
||||
.pllu = {.n = 50, .m = 1, .p = 0, .cpcon = 2},
|
||||
.plldp = {.n = 28, .m = 1, .p = 3}, /* 266 MHz */
|
||||
},
|
||||
[OSC_FREQ_OSC48]{
|
||||
.khz = 48000,
|
||||
|
|
@ -143,6 +151,7 @@ struct {
|
|||
.pllc = {.n = 50, .m = 1, .p = 0},
|
||||
.plld = {.n = 925, .m = 12, .p = 0, .cpcon = 12},
|
||||
.pllu = {.n = 80, .m = 1, .p = 0, .cpcon = 3},
|
||||
.plldp = {.n = 22, .m = 1, .p = 3}, /* 264 MHz */
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -189,6 +198,23 @@ static void adjust_pllp_out_freqs(void)
|
|||
writel(reg, &clk_rst->pllp_outb);
|
||||
}
|
||||
|
||||
#define SOR0_CLK_SEL0 (1 << 14)
|
||||
#define SOR0_CLK_SEL1 (1 << 15)
|
||||
|
||||
void sor_clock_stop(void)
|
||||
{
|
||||
/* The Serial Output Resource clock has to be off
|
||||
* before we start the plldp. Learned the hard way.
|
||||
* FIXME: this has to be cleaned up a bit more.
|
||||
* Waiting on some new info from Nvidia.
|
||||
*/
|
||||
clrbits_le32(&clk_rst->clk_src_sor, SOR0_CLK_SEL0 | SOR0_CLK_SEL1);
|
||||
}
|
||||
|
||||
void sor_clock_start(void)
|
||||
{
|
||||
setbits_le32(&clk_rst->clk_src_sor, SOR0_CLK_SEL0 | SOR0_CLK_SEL1);
|
||||
}
|
||||
static void init_pll(u32 *base, u32 *misc, const union pll_fields pll)
|
||||
{
|
||||
u32 dividers = pll.div.n << PLL_BASE_DIVN_SHIFT |
|
||||
|
|
@ -197,7 +223,6 @@ static void init_pll(u32 *base, u32 *misc, const union pll_fields pll)
|
|||
|
||||
/* Write dividers but BYPASS the PLL while we're messing with it. */
|
||||
writel(dividers | PLL_BASE_BYPASS, base);
|
||||
|
||||
/* Set CPCON field (defaults to 0 if it doesn't exist for this PLL) */
|
||||
writel(pll.div.cpcon << PLL_MISC_CPCON_SHIFT, misc);
|
||||
|
||||
|
|
@ -237,6 +262,32 @@ static void init_utmip_pll(void)
|
|||
setbits_le32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */
|
||||
}
|
||||
|
||||
/* Graphics just has to be different. There's a few more bits we
|
||||
* need to set in here, but it makes sense just to restrict all the
|
||||
* special bits to this one function.
|
||||
*/
|
||||
void graphics_clock(void)
|
||||
{
|
||||
int osc = clock_get_osc_bits();
|
||||
u32 *cfg = &clk_rst->plldp_ss_cfg;
|
||||
/* the vendor code sets the dither bit (28)
|
||||
* an undocumented bit (24)
|
||||
* and clamp while we mess with it (22)
|
||||
* Dither is pretty important to display port
|
||||
* so we really do need to handle these bits.
|
||||
* I'm not willing to not clamp it, even if
|
||||
* it might "mostly work" with it not set,
|
||||
* I don't want to find out in a few months
|
||||
* that it is needed.
|
||||
*/
|
||||
u32 scfg = (1<<28) | (1<<24) | (1<<22);
|
||||
writel(scfg, cfg);
|
||||
init_pll(&clk_rst->plldp_base, &clk_rst->plldp_misc, osc_table[osc].plldp);
|
||||
/* leave dither and undoc bits set, release clamp */
|
||||
scfg = (1<<28) | (1<<24);
|
||||
writel(scfg, cfg);
|
||||
}
|
||||
|
||||
/* Initialize the UART and put it on CLK_M so we can use it during clock_init().
|
||||
* Will later move it to PLLP in clock_config(). The divisor must be very small
|
||||
* to accomodate 12KHz OSCs, so we override the 16.0 UART divider with the 15.1
|
||||
|
|
|
|||
|
|
@ -647,7 +647,7 @@ void dp_io_powerup(void)
|
|||
|
||||
// struct clk_rst_ctlr *clkrst =
|
||||
// (struct clk_rst_ctlr *)TEGRA_CLK_RST_BASE;
|
||||
u32 reg_val;
|
||||
|
||||
|
||||
printk(BIOS_SPEW, "%s: entry\n", __func__);
|
||||
|
||||
|
|
@ -655,26 +655,8 @@ void dp_io_powerup(void)
|
|||
printk(BIOS_SPEW, "JZ: %s: %d: do nothing, ret\n", __func__, __LINE__);
|
||||
return;
|
||||
#endif
|
||||
|
||||
#define SOR0_CLK_SEL0 (1 << 14)
|
||||
#define SOR0_CLK_SEL1 (1 << 15)
|
||||
// REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0, SOR0_CLK_SEL1, 0);
|
||||
// REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0, SOR0_CLK_SEL0, 0);//sor safe clock
|
||||
reg_val = READL((void *)(0x60006000 + 0x414));
|
||||
reg_val &= ~(SOR0_CLK_SEL0 | SOR0_CLK_SEL1);
|
||||
WRITEL(reg_val, (void *)(0x60006000 + 0x414));
|
||||
|
||||
// clock(PLLDP, 270)
|
||||
WRITEL(0, (void *)(0x60006000 + 0x594)); // plldp_misc
|
||||
WRITEL(0x11400000, (void *)(0x60006000 + 0x598)); // plldp_ss_cfg
|
||||
WRITEL(0x80305a01, (void *)(0x60006000 + 0x590));// plldp_base, 12 * 90 / 4 = 270
|
||||
WRITEL(0x11400000, (void *)(0x60006000 + 0x598)); // plldp_ss_cfg
|
||||
WRITEL(0x40000000, (void *)(0x60006000 + 0x594)); // misc: enable lock
|
||||
WRITEL(0xc0305a01, (void *)(0x60006000 + 0x590)); // base: enable
|
||||
WRITEL(0xd8305a01, (void *)(0x60006000 + 0x590)); // base: check lock
|
||||
WRITEL(0x58305a01, (void *)(0x60006000 + 0x590)); // base: disable bypass
|
||||
WRITEL(0x11000000, (void *)(0x60006000 + 0x598)); // release clamp
|
||||
udelay(10); // wait for plldp ready
|
||||
sor_clock_stop();
|
||||
graphics_clock();
|
||||
|
||||
SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, (6 << 2) | 2);//select PLLDP, lowest speed(6x)
|
||||
SOR_WRITE(SOR_NV_PDISP_SOR_DP_PADCTL0_0, 0x00800000); //set PDCAL
|
||||
|
|
@ -888,11 +870,12 @@ void dp_link_training(u32 lanes, u32 speed)
|
|||
SOR_WRITE(SOR_NV_PDISP_SOR_CLK_CNTRL_0, ((speed << 2) | 2));
|
||||
udelay(100);
|
||||
|
||||
//REG(CLK_RST_CONTROLLER_CLK_SOURCE_SOR0_0,SOR0_CLK_SEL0, 1) //sor clk=pad macro output
|
||||
sor_clock_start();
|
||||
#if 0
|
||||
reg_val = readl((void *)(0x60006000 + 0x414));
|
||||
reg_val |= SOR0_CLK_SEL0;
|
||||
|
||||
writel(reg_val, (void *)(0x60006000 + 0x414));
|
||||
#endif
|
||||
|
||||
SOR_WRITE(SOR_NV_PDISP_SOR_DP_LINKCTL0_0,
|
||||
(((0xF >> (4 - lanes)) << 16) | 1));
|
||||
|
|
|
|||
|
|
@ -239,5 +239,9 @@ void clock_cpu0_config_and_reset(void * entry);
|
|||
void clock_enable_clear_reset(u32 l, u32 h, u32 u, u32 v, u32 w, u32 x);
|
||||
void clock_init(void);
|
||||
void clock_init_arm_generic_timer(void);
|
||||
void sor_clock_stop(void);
|
||||
void sor_clock_start(void);
|
||||
void graphics_clock(void);
|
||||
|
||||
#endif /* __SOC_NVIDIA_TEGRA124_CLOCK_H__ */
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue