Pi Firmware: refactor so changing PLLA/C/D is easier

Change-Id: I11dcb5d4994ebbb371af3e4fd30ececd6400034e
pull/105/head
David Banks 2019-04-29 20:25:47 +01:00
rodzic 0e671ea107
commit cba658095c
2 zmienionych plików z 99 dodań i 26 usunięć

Wyświetl plik

@ -96,11 +96,6 @@
#define BIT_BOTH_BUFFERS (BIT_DRAW_BUFFER | BIT_DISP_BUFFER)
// Define the pixel clock for sampling
#define PLL_PER_DIVIDER 4 // This gives a default PLLA_PER clock of 600MHz
#define GPCLK_SOURCE 4 // PLLA_PER used as source
#define DEFAULT_GPCLK_DIVISOR 6 // 600MHz / 6 = 100MHz
// Pi 2/3 Multicore options
#if defined(RPI2) || defined(RPI3)
@ -290,10 +285,21 @@ typedef struct {
#define PIXELVALVE2_VERTA (volatile uint32_t *)(PERIPHERAL_BASE + 0x807014)
#define PIXELVALVE2_VERTB (volatile uint32_t *)(PERIPHERAL_BASE + 0x807018)
#define PM_RSTC (volatile uint32_t *)(PERIPHERAL_BASE + 0x10001c)
#define PM_WDOG (volatile uint32_t *)(PERIPHERAL_BASE + 0x100024)
#define PM_PASSWORD 0x5a000000
#define PM_RSTC_WRCFG_FULL_RESET 0x00000020
#define CM_PASSWORD 0x5a000000
#define CM_PLLA_LOADCORE (1 << 4)
#define CM_PLLA_HOLDCORE (1 << 5)
#define CM_PLLA_LOADPER (1 << 6)
#define CM_PLLA_HOLDPER (1 << 7)
#define A2W_PLL_CHANNEL_DISABLE (1 << 8)
#define GZ_CLK_BUSY (1 << 7)
#define GZ_CLK_ENA (1 << 4)
#define GP_CLK1_CTL (volatile uint32_t *)(PERIPHERAL_BASE + 0x101078)
#define GP_CLK1_DIV (volatile uint32_t *)(PERIPHERAL_BASE + 0x10107C)
#define CM_PLLA (volatile uint32_t *)(0x20101104)
#endif

Wyświetl plik

@ -28,17 +28,68 @@
typedef void (*func_ptr)();
#define CM_PASSWORD 0x5a000000
#define CM_PLLA_LOADCORE (1 << 4)
#define CM_PLLA_HOLDCORE (1 << 5)
#define CM_PLLA_LOADPER (1 << 6)
#define CM_PLLA_HOLDPER (1 << 7)
#define A2W_PLL_CHANNEL_DISABLE (1 << 8)
#define GZ_CLK_BUSY (1 << 7)
#define GZ_CLK_ENA (1 << 4)
#define GP_CLK1_CTL (volatile uint32_t *)(PERIPHERAL_BASE + 0x101078)
#define GP_CLK1_DIV (volatile uint32_t *)(PERIPHERAL_BASE + 0x10107C)
#define CM_PLLA (volatile uint32_t *)(0x20101104)
// =============================================================
// Define the PLL to be used for the sampling clock
// =============================================================
//
// Choose between PLLA, PLLC and PLLD
//
// PLLA - not otherwise used
// PLLC - used for the Core Clock
// PLLD - possibly used for the SDRAM Clock, so might overclock it by 20%
//
// TODO: PLLA doesn't currently start on the Pi2/Pi3
//
// Power-on defaults are values for the Pi Zero
// SYS_CLK_DIVIDER is the ratio between PLLC and the Core Clock
// This is typically 3 or 4, depending on the Pi Model. We need
// to know this to correct serial speed when PLLC used.
#if defined(RPI3)
#define USE_PLLC
#define SYS_CLK_DIVIDER 3
#elif defined(RPI2)
#define USE_PLLC
#define SYS_CLK_DIVIDER 4
#else
#define USE_PLLA
#define SYS_CLK_DIVIDER 3
#endif
#ifdef USE_PLLA
#define PLL_NAME "PLLA" // power-on default = off
#define GPCLK_SOURCE 4 // PLLA_PER used as source
#define DEFAULT_GPCLK_DIVISOR 6 // 600MHz / 6 = 100MHz
#define PLL_CTRL PLLA_CTRL
#define PLL_FRAC PLLA_FRAC
#define PLL_SCALE 2
#define MIN_PLL_FREQ 800000000 // PLLA_PER = 400MHz
#define MAX_PLL_FREQ 1200000000 // PLLA_PER = 600MHz
#endif
#ifdef USE_PLLC
#define PLL_NAME "PLLC" // power-on default = 1200MHz
#define GPCLK_SOURCE 5 // PLLC_PER used as source
#define DEFAULT_GPCLK_DIVISOR 12 // 1200MHz / 12 = 100MHz
#define PLL_CTRL PLLC_CTRL
#define PLL_FRAC PLLC_FRAC
#define PLL_SCALE 1
#define MIN_PLL_FREQ 900000000 // PLLC_PER = 900MHz
#define MAX_PLL_FREQ 1200000000 // PLLC_PER = 1200MHz
#endif
#ifdef USE_PLLD
#define PLL_NAME "PLLD" // power-on default = 500MHz
#define GPCLK_SOURCE 6 // PLLD_PER used as source
#define DEFAULT_GPCLK_DIVISOR 5 // 500MHz / 5 = 100MHz
#define PLL_CTRL PLLD_CTRL
#define PLL_FRAC PLLD_FRAC
#define PLL_SCALE 2
#define MIN_PLL_FREQ 800000000 // PLLD_PER = 400MHz
#define MAX_PLL_FREQ 1200000000 // PLLD_PER = 600MHz
#endif
// =============================================================
// Forward declarations
@ -535,9 +586,9 @@ static int calibrate_sampling_clock() {
log_info(" Error adjusted clock = %d Hz", adjusted_clock);
// Pick the best value for pll_freq and gpclk_divisor
int pll_scale = PLL_PER_DIVIDER / 2; // This comes from the value in PLL_PER (4)
int min_pll_freq = 800000000; // This gives a GPCLK soource of 400MHz
int max_pll_freq = 1200000000; // This gives a GPCLK souurce of 600MHz
int pll_scale = PLL_SCALE; // defined at the top
int min_pll_freq = MIN_PLL_FREQ; // defined at the top
int max_pll_freq = MAX_PLL_FREQ; // defined at the top
int gpclk_divisor = max_pll_freq / pll_scale / new_clock;
int pll_freq = new_clock * pll_scale * gpclk_divisor ;
log_info(" GPCLK Divisor = %d", gpclk_divisor);
@ -555,15 +606,20 @@ static int calibrate_sampling_clock() {
// If the clock has changed from it's previous value, then actually change it
if (pll_freq != old_pll_freq) {
set_pll_frequency(((double) pll_freq) / 1e6, PLLA_CTRL, PLLA_FRAC);
set_pll_frequency(((double) pll_freq) / 1e6, PLL_CTRL, PLL_FRAC);
#ifdef USE_PLLC
// Reinitialize the UART as the Core Clock has changed
RPI_AuxMiniUartInit_With_Freq(115200, 8, pll_freq / SYS_CLK_DIVIDER);
#endif
// And remember for next time
old_pll_freq = pll_freq;
}
// TODO: this should be superfluous (as the GPU is not changing the core clock)
// However, if we remove it, the next osd_update_palette() call hangs
int core_clock = get_clock_rate(CORE_CLK_ID);
log_info(" Core clock freq = %d Hz", core_clock);
get_clock_rate(CORE_CLK_ID);
// Finally, set the new divisor
log_debug("Setting up divisor");
@ -847,7 +903,6 @@ int recalculate_hdmi_clock_line_locked_update(int force) {
}
}
// Configure PLLA so we can use it as a sampling clock source
//
// The logic to configure PLLA conmes from the Linux Kernel clk-bcm2835
@ -856,7 +911,7 @@ int recalculate_hdmi_clock_line_locked_update(int force) {
// - bcm2835_pll_divider_set_rate
// - bcm2835_pll_divider_on
// https://elixir.bootlin.com/linux/v4.4.70/source/drivers/clk/bcm/clk-bcm2835.c
#ifdef USE_PLLA
static void configure_plla(int divider) {
// Log the before register values
@ -882,6 +937,7 @@ static void configure_plla(int divider) {
// Log the before register values
log_plla();
}
#endif
static void init_hardware() {
int i;
@ -922,8 +978,19 @@ static void init_hardware() {
// Configure the GPCLK pin as a GPCLK
RPI_SetGpioPinFunction(GPCLK_PIN, FS_ALT5);
log_info("Using %s as the sampling clock", PLL_NAME);
// Log all the PLL values
log_plla();
log_pllb();
log_pllc();
log_plld();
log_pllh();
#ifdef USE_PLLA
// Enable the PLLA_PER divider
configure_plla(PLL_PER_DIVIDER);
configure_plla(4);
#endif
// The divisor us now the same for both modes
log_debug("Setting up divisor");