int tegra_set_emc(const void *blob, unsigned rate) { struct emc_ctlr *emc; const u32 *table; int err, i; err = decode_emc(blob, rate, &emc, &table); if (err) { debug("Warning: no valid EMC (%d), memory timings unset\n", err); return err; } debug("%s: Table found, setting EMC values as follows:\n", __func__); for (i = 0; i < TEGRA_EMC_NUM_REGS; i++) { u32 value = fdt32_to_cpu(table[i]); u32 addr = (uintptr_t)emc + emc_reg_addr[i]; debug(" %#x: %#x\n", addr, value); writel(value, addr); } /* trigger emc with new settings */ clock_adjust_periph_pll_div(PERIPH_ID_EMC, CLOCK_ID_MEMORY, clock_get_rate(CLOCK_ID_MEMORY), NULL); debug("EMC clock set to %lu\n", clock_get_periph_rate(PERIPH_ID_EMC, CLOCK_ID_MEMORY)); return 0; }
static void serial_setbrg_dev(void) { struct s5p_uart *uart = (struct s5p_uart *)base_port; u32 uclk; u32 baudrate = CONFIG_TTYS0_BAUD; u32 val; // All UARTs share the same clock. uclk = clock_get_periph_rate(PERIPH_ID_UART3); val = uclk / baudrate; writel(val / 16 - 1, &uart->ubrdiv); /* * FIXME(dhendrix): the original uart.h had a "br_rest" value which * does not seem relevant to the exynos5250... not entirely sure * where/if we need to worry about it here */ #if 0 if (s5p_uart_divslot()) writel(udivslot[val % 16], &uart->rest.slot); else writeb(val % 16, &uart->rest.value); #endif }
int pwm_init(int pwm_id, int div, int invert) { u32 val; const struct s5p_timer *pwm = (struct s5p_timer *)samsung_get_base_timer(); unsigned long ticks_per_period; unsigned int offset, prescaler; /* * Timer Freq(HZ) = * PWM_CLK / { (prescaler_value + 1) * (divider_value) } */ val = readl(&pwm->tcfg0); if (pwm_id < 2) { prescaler = PRESCALER_0; val &= ~0xff; val |= (prescaler & 0xff); } else { prescaler = PRESCALER_1; val &= ~(0xff << 8); val |= (prescaler & 0xff) << 8; } writel(val, &pwm->tcfg0); val = readl(&pwm->tcfg1); val &= ~(0xf << MUX_DIV_SHIFT(pwm_id)); val |= (div & 0xf) << MUX_DIV_SHIFT(pwm_id); writel(val, &pwm->tcfg1); if (pwm_id == 4) { /* * TODO(sjg): Use this as a countdown timer for now. We count * down from the maximum value to 0, then reset. */ ticks_per_period = -1UL; } else { const unsigned long pwm_hz = 1000; unsigned long timer_rate_hz = clock_get_periph_rate( PERIPH_ID_PWM0) / ((prescaler + 1) * (1 << div)); ticks_per_period = timer_rate_hz / pwm_hz; } /* set count value */ offset = pwm_id * 3; writel(ticks_per_period, &pwm->tcntb0 + offset); val = readl(&pwm->tcon) & ~(0xf << TCON_OFFSET(pwm_id)); if (invert && (pwm_id < 4)) val |= TCON_INVERTER(pwm_id); writel(val, &pwm->tcon); pwm_enable(pwm_id); return 0; }
static ulong tegra_car_clk_get_rate(struct clk *clk) { enum clock_id parent; debug("%s(clk=%p) (dev=%p, id=%lu)\n", __func__, clk, clk->dev, clk->id); parent = clock_get_periph_parent(clk->id); return clock_get_periph_rate(clk->id, parent); }
static unsigned long pwm_calc_tin(int pwm_id, unsigned long freq) { unsigned long tin_parent_rate; unsigned int div; tin_parent_rate = clock_get_periph_rate(PERIPH_ID_PWM0); for (div = 2; div <= 16; div *= 2) { if ((tin_parent_rate / (div << 16)) < freq) return tin_parent_rate / div; } return tin_parent_rate / 16; }
static int update_display_mode(struct dc_disp_reg *disp, struct tegra_lcd_priv *priv) { unsigned long val; unsigned long rate; unsigned long div; writel(0x0, &disp->disp_timing_opt); write_pair(priv, FDT_LCD_TIMING_REF_TO_SYNC, &disp->ref_to_sync); write_pair(priv, FDT_LCD_TIMING_SYNC_WIDTH, &disp->sync_width); write_pair(priv, FDT_LCD_TIMING_BACK_PORCH, &disp->back_porch); write_pair(priv, FDT_LCD_TIMING_FRONT_PORCH, &disp->front_porch); writel(priv->width | (priv->height << 16), &disp->disp_active); val = DE_SELECT_ACTIVE << DE_SELECT_SHIFT; val |= DE_CONTROL_NORMAL << DE_CONTROL_SHIFT; writel(val, &disp->data_enable_opt); val = DATA_FORMAT_DF1P1C << DATA_FORMAT_SHIFT; val |= DATA_ALIGNMENT_MSB << DATA_ALIGNMENT_SHIFT; val |= DATA_ORDER_RED_BLUE << DATA_ORDER_SHIFT; writel(val, &disp->disp_interface_ctrl); /* * The pixel clock divider is in 7.1 format (where the bottom bit * represents 0.5). Here we calculate the divider needed to get from * the display clock (typically 600MHz) to the pixel clock. We round * up or down as requried. */ rate = clock_get_periph_rate(PERIPH_ID_DISP1, CLOCK_ID_CGENERAL); div = ((rate * 2 + priv->pixel_clock / 2) / priv->pixel_clock) - 2; debug("Display clock %lu, divider %lu\n", rate, div); writel(0x00010001, &disp->shift_clk_opt); val = PIXEL_CLK_DIVIDER_PCD1 << PIXEL_CLK_DIVIDER_SHIFT; val |= div << SHIFT_CLK_DIVIDER_SHIFT; writel(val, &disp->disp_clk_ctrl); return 0; }
static void serial_setbrg_dev(struct s5p_uart *uart) { u32 uclk; u32 val; // All UARTs share the same clock. uclk = clock_get_periph_rate(PERIPH_ID_UART3); val = uclk / default_baudrate(); write32(&uart->ubrdiv, val / 16 - 1); /* * FIXME(dhendrix): the original uart.h had a "br_rest" value which * does not seem relevant to the exynos5420... not entirely sure * where/if we need to worry about it here */ #if 0 if (s5p_uart_divslot()) writel(udivslot[val % 16], &uart->rest.slot); else writeb(val % 16, &uart->rest.value); #endif }