📄 at32ap7000.c
字号:
/* * Copyright (C) 2005-2006 Atmel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/clk.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/platform_device.h>#include <linux/dma-mapping.h>#include <linux/spi/spi.h>#include <asm/io.h>#include <asm/arch/at32ap7000.h>#include <asm/arch/board.h>#include <asm/arch/portmux.h>#include <video/atmel_lcdc.h>#include "clock.h"#include "hmatrix.h"#include "pio.h"#include "pm.h"#define PBMEM(base) \ { \ .start = base, \ .end = base + 0x3ff, \ .flags = IORESOURCE_MEM, \ }#define IRQ(num) \ { \ .start = num, \ .end = num, \ .flags = IORESOURCE_IRQ, \ }#define NAMED_IRQ(num, _name) \ { \ .start = num, \ .end = num, \ .name = _name, \ .flags = IORESOURCE_IRQ, \ }/* REVISIT these assume *every* device supports DMA, but several * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more. */#define DEFINE_DEV(_name, _id) \static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \static struct platform_device _name##_id##_device = { \ .name = #_name, \ .id = _id, \ .dev = { \ .dma_mask = &_name##_id##_dma_mask, \ .coherent_dma_mask = DMA_32BIT_MASK, \ }, \ .resource = _name##_id##_resource, \ .num_resources = ARRAY_SIZE(_name##_id##_resource), \}#define DEFINE_DEV_DATA(_name, _id) \static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \static struct platform_device _name##_id##_device = { \ .name = #_name, \ .id = _id, \ .dev = { \ .dma_mask = &_name##_id##_dma_mask, \ .platform_data = &_name##_id##_data, \ .coherent_dma_mask = DMA_32BIT_MASK, \ }, \ .resource = _name##_id##_resource, \ .num_resources = ARRAY_SIZE(_name##_id##_resource), \}#define select_peripheral(pin, periph, flags) \ at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)#define DEV_CLK(_name, devname, bus, _index) \static struct clk devname##_##_name = { \ .name = #_name, \ .dev = &devname##_device.dev, \ .parent = &bus##_clk, \ .mode = bus##_clk_mode, \ .get_rate = bus##_clk_get_rate, \ .index = _index, \}static DEFINE_SPINLOCK(pm_lock);unsigned long at32ap7000_osc_rates[3] = { [0] = 32768, /* FIXME: these are ATSTK1002-specific */ [1] = 20000000, [2] = 12000000,};static unsigned long osc_get_rate(struct clk *clk){ return at32ap7000_osc_rates[clk->index];}static unsigned long pll_get_rate(struct clk *clk, unsigned long control){ unsigned long div, mul, rate; if (!(control & PM_BIT(PLLEN))) return 0; div = PM_BFEXT(PLLDIV, control) + 1; mul = PM_BFEXT(PLLMUL, control) + 1; rate = clk->parent->get_rate(clk->parent); rate = (rate + div / 2) / div; rate *= mul; return rate;}static unsigned long pll0_get_rate(struct clk *clk){ u32 control; control = pm_readl(PLL0); return pll_get_rate(clk, control);}static unsigned long pll1_get_rate(struct clk *clk){ u32 control; control = pm_readl(PLL1); return pll_get_rate(clk, control);}/* * The AT32AP7000 has five primary clock sources: One 32kHz * oscillator, two crystal oscillators and two PLLs. */static struct clk osc32k = { .name = "osc32k", .get_rate = osc_get_rate, .users = 1, .index = 0,};static struct clk osc0 = { .name = "osc0", .get_rate = osc_get_rate, .users = 1, .index = 1,};static struct clk osc1 = { .name = "osc1", .get_rate = osc_get_rate, .index = 2,};static struct clk pll0 = { .name = "pll0", .get_rate = pll0_get_rate, .parent = &osc0,};static struct clk pll1 = { .name = "pll1", .get_rate = pll1_get_rate, .parent = &osc0,};/* * The main clock can be either osc0 or pll0. The boot loader may * have chosen one for us, so we don't really know which one until we * have a look at the SM. */static struct clk *main_clock;/* * Synchronous clocks are generated from the main clock. The clocks * must satisfy the constraint * fCPU >= fHSB >= fPB * i.e. each clock must not be faster than its parent. */static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift){ return main_clock->get_rate(main_clock) >> shift;};static void cpu_clk_mode(struct clk *clk, int enabled){ unsigned long flags; u32 mask; spin_lock_irqsave(&pm_lock, flags); mask = pm_readl(CPU_MASK); if (enabled) mask |= 1 << clk->index; else mask &= ~(1 << clk->index); pm_writel(CPU_MASK, mask); spin_unlock_irqrestore(&pm_lock, flags);}static unsigned long cpu_clk_get_rate(struct clk *clk){ unsigned long cksel, shift = 0; cksel = pm_readl(CKSEL); if (cksel & PM_BIT(CPUDIV)) shift = PM_BFEXT(CPUSEL, cksel) + 1; return bus_clk_get_rate(clk, shift);}static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply){ u32 control; unsigned long parent_rate, child_div, actual_rate, div; parent_rate = clk->parent->get_rate(clk->parent); control = pm_readl(CKSEL); if (control & PM_BIT(HSBDIV)) child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1); else child_div = 1; if (rate > 3 * (parent_rate / 4) || child_div == 1) { actual_rate = parent_rate; control &= ~PM_BIT(CPUDIV); } else { unsigned int cpusel; div = (parent_rate + rate / 2) / rate; if (div > child_div) div = child_div; cpusel = (div > 1) ? (fls(div) - 2) : 0; control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control); actual_rate = parent_rate / (1 << (cpusel + 1)); } pr_debug("clk %s: new rate %lu (actual rate %lu)\n", clk->name, rate, actual_rate); if (apply) pm_writel(CKSEL, control); return actual_rate;}static void hsb_clk_mode(struct clk *clk, int enabled){ unsigned long flags; u32 mask; spin_lock_irqsave(&pm_lock, flags); mask = pm_readl(HSB_MASK); if (enabled) mask |= 1 << clk->index; else mask &= ~(1 << clk->index); pm_writel(HSB_MASK, mask); spin_unlock_irqrestore(&pm_lock, flags);}static unsigned long hsb_clk_get_rate(struct clk *clk){ unsigned long cksel, shift = 0; cksel = pm_readl(CKSEL); if (cksel & PM_BIT(HSBDIV)) shift = PM_BFEXT(HSBSEL, cksel) + 1; return bus_clk_get_rate(clk, shift);}static void pba_clk_mode(struct clk *clk, int enabled){ unsigned long flags; u32 mask; spin_lock_irqsave(&pm_lock, flags); mask = pm_readl(PBA_MASK); if (enabled) mask |= 1 << clk->index; else mask &= ~(1 << clk->index); pm_writel(PBA_MASK, mask); spin_unlock_irqrestore(&pm_lock, flags);}static unsigned long pba_clk_get_rate(struct clk *clk){ unsigned long cksel, shift = 0; cksel = pm_readl(CKSEL); if (cksel & PM_BIT(PBADIV)) shift = PM_BFEXT(PBASEL, cksel) + 1; return bus_clk_get_rate(clk, shift);}static void pbb_clk_mode(struct clk *clk, int enabled){ unsigned long flags; u32 mask; spin_lock_irqsave(&pm_lock, flags); mask = pm_readl(PBB_MASK); if (enabled) mask |= 1 << clk->index; else mask &= ~(1 << clk->index); pm_writel(PBB_MASK, mask); spin_unlock_irqrestore(&pm_lock, flags);}static unsigned long pbb_clk_get_rate(struct clk *clk){ unsigned long cksel, shift = 0; cksel = pm_readl(CKSEL); if (cksel & PM_BIT(PBBDIV)) shift = PM_BFEXT(PBBSEL, cksel) + 1; return bus_clk_get_rate(clk, shift);}static struct clk cpu_clk = { .name = "cpu", .get_rate = cpu_clk_get_rate, .set_rate = cpu_clk_set_rate, .users = 1,};static struct clk hsb_clk = { .name = "hsb", .parent = &cpu_clk, .get_rate = hsb_clk_get_rate,};static struct clk pba_clk = { .name = "pba", .parent = &hsb_clk, .mode = hsb_clk_mode, .get_rate = pba_clk_get_rate, .index = 1,};static struct clk pbb_clk = { .name = "pbb", .parent = &hsb_clk, .mode = hsb_clk_mode, .get_rate = pbb_clk_get_rate, .users = 1, .index = 2,};/* -------------------------------------------------------------------- * Generic Clock operations * -------------------------------------------------------------------- */static void genclk_mode(struct clk *clk, int enabled){ u32 control; control = pm_readl(GCCTRL(clk->index)); if (enabled) control |= PM_BIT(CEN); else control &= ~PM_BIT(CEN); pm_writel(GCCTRL(clk->index), control);}static unsigned long genclk_get_rate(struct clk *clk){ u32 control; unsigned long div = 1; control = pm_readl(GCCTRL(clk->index)); if (control & PM_BIT(DIVEN)) div = 2 * (PM_BFEXT(DIV, control) + 1); return clk->parent->get_rate(clk->parent) / div;}static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply){ u32 control; unsigned long parent_rate, actual_rate, div; parent_rate = clk->parent->get_rate(clk->parent); control = pm_readl(GCCTRL(clk->index)); if (rate > 3 * parent_rate / 4) { actual_rate = parent_rate; control &= ~PM_BIT(DIVEN); } else { div = (parent_rate + rate) / (2 * rate) - 1; control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN); actual_rate = parent_rate / (2 * (div + 1)); } dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n", clk->name, rate, actual_rate); if (apply) pm_writel(GCCTRL(clk->index), control); return actual_rate;}int genclk_set_parent(struct clk *clk, struct clk *parent){ u32 control; dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n", clk->name, parent->name, clk->parent->name); control = pm_readl(GCCTRL(clk->index)); if (parent == &osc1 || parent == &pll1) control |= PM_BIT(OSCSEL); else if (parent == &osc0 || parent == &pll0) control &= ~PM_BIT(OSCSEL); else return -EINVAL; if (parent == &pll0 || parent == &pll1) control |= PM_BIT(PLLSEL); else control &= ~PM_BIT(PLLSEL); pm_writel(GCCTRL(clk->index), control); clk->parent = parent; return 0;}static void __init genclk_init_parent(struct clk *clk){ u32 control; struct clk *parent; BUG_ON(clk->index > 7); control = pm_readl(GCCTRL(clk->index)); if (control & PM_BIT(OSCSEL)) parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1; else parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0; clk->parent = parent;}/* -------------------------------------------------------------------- * System peripherals * -------------------------------------------------------------------- */static struct resource at32_pm0_resource[] = { { .start = 0xfff00000, .end = 0xfff0007f, .flags = IORESOURCE_MEM, }, IRQ(20),};static struct resource at32ap700x_rtc0_resource[] = { { .start = 0xfff00080, .end = 0xfff000af, .flags = IORESOURCE_MEM, }, IRQ(21),};static struct resource at32_wdt0_resource[] = { { .start = 0xfff000b0, .end = 0xfff000cf, .flags = IORESOURCE_MEM, },};static struct resource at32_eic0_resource[] = { { .start = 0xfff00100, .end = 0xfff0013f, .flags = IORESOURCE_MEM, }, IRQ(19),};DEFINE_DEV(at32_pm, 0);DEFINE_DEV(at32ap700x_rtc, 0);DEFINE_DEV(at32_wdt, 0);DEFINE_DEV(at32_eic, 0);/* * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this * is always running. */static struct clk at32_pm_pclk = { .name = "pclk", .dev = &at32_pm0_device.dev, .parent = &pbb_clk, .mode = pbb_clk_mode, .get_rate = pbb_clk_get_rate, .users = 1, .index = 0,};static struct resource intc0_resource[] = { PBMEM(0xfff00400),};struct platform_device at32_intc0_device = { .name = "intc", .id = 0, .resource = intc0_resource, .num_resources = ARRAY_SIZE(intc0_resource),};DEV_CLK(pclk, at32_intc0, pbb, 1);static struct clk ebi_clk = { .name = "ebi", .parent = &hsb_clk, .mode = hsb_clk_mode, .get_rate = hsb_clk_get_rate, .users = 1,};static struct clk hramc_clk = { .name = "hramc", .parent = &hsb_clk, .mode = hsb_clk_mode, .get_rate = hsb_clk_get_rate, .users = 1, .index = 3,};static struct resource smc0_resource[] = { PBMEM(0xfff03400),};DEFINE_DEV(smc, 0);DEV_CLK(pclk, smc0, pbb, 13);DEV_CLK(mck, smc0, hsb, 0);static struct platform_device pdc_device = { .name = "pdc", .id = 0,};DEV_CLK(hclk, pdc, hsb, 4);DEV_CLK(pclk, pdc, pba, 16);static struct clk pico_clk = { .name = "pico", .parent = &cpu_clk, .mode = cpu_clk_mode, .get_rate = cpu_clk_get_rate, .users = 1,};static struct resource dmaca0_resource[] = { { .start = 0xff200000, .end = 0xff20ffff, .flags = IORESOURCE_MEM, }, IRQ(2),};DEFINE_DEV(dmaca, 0);DEV_CLK(hclk, dmaca0, hsb, 10);/* -------------------------------------------------------------------- * HMATRIX * -------------------------------------------------------------------- */static struct clk hmatrix_clk = { .name = "hmatrix_clk", .parent = &pbb_clk, .mode = pbb_clk_mode,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -