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:
Ronald G. Minnich 2013-10-30 14:25:00 -07:00 committed by chrome-internal-fetch
commit b8eb6ab4cd
3 changed files with 63 additions and 25 deletions

View file

@ -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

View file

@ -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));

View file

@ -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__ */