/* * File : dm365.c * This file is part of RT-Thread RTOS * COPYRIGHT (C) 2006, RT-Thread Development Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Change Logs: * Date Author Notes * 2010-11-13 weety first version */ #include #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static rt_uint32_t commonrate; static rt_uint32_t div_by_four; static rt_uint32_t div_by_six; static rt_uint32_t armrate; static rt_uint32_t fixedrate; static rt_uint32_t ddrrate; static rt_uint32_t voicerate; static rt_uint32_t mmcsdrate; static rt_uint32_t vpssrate, vencrate_sd, vencrate_hd; /* Four Transfer Controllers on DM365 */ static const rt_int8_t dm365_queue_tc_mapping[][2] = { /* {event queue no, TC no} */ {0, 0}, {1, 1}, {2, 2}, {3, 3}, {-1, -1}, }; static const rt_int8_t dm365_queue_priority_mapping[][2] = { /* {event queue no, Priority} */ {0, 7}, {1, 7}, {2, 7}, {3, 0}, {-1, -1}, }; static struct edma_soc_info edma_cc0_info = { .n_channel = 64, .n_region = 4, .n_slot = 256, .n_tc = 4, .n_cc = 1, .queue_tc_mapping = dm365_queue_tc_mapping, .queue_priority_mapping = dm365_queue_priority_mapping, .default_queue = EVENTQ_3, }; static struct edma_soc_info *dm365_edma_info[EDMA_MAX_CC] = { &edma_cc0_info, }; static rt_list_t clocks; struct clk { char name[32]; rt_uint32_t *rate_hz; struct clk *parent; rt_list_t node; }; static struct clk davinci_dm365_clks[] = { { .name = "ARMCLK", .rate_hz = &armrate, }, { .name = "UART0", .rate_hz = &fixedrate, }, { .name = "UART1", .rate_hz = &commonrate, }, { .name = "HPI", .rate_hz = &commonrate, }, { .name = "EMACCLK", .rate_hz = &commonrate, }, { .name = "I2CCLK", .rate_hz = &fixedrate, }, { .name = "McBSPCLK", .rate_hz = &commonrate, }, { .name = "MMCSDCLK0", .rate_hz = &mmcsdrate, }, { .name = "MMCSDCLK1", .rate_hz = &mmcsdrate, }, { .name = "SPICLK", .rate_hz = &commonrate, }, { .name = "gpio", .rate_hz = &commonrate, }, { .name = "AEMIFCLK", .rate_hz = &commonrate, }, { .name = "PWM0_CLK", .rate_hz = &fixedrate, }, { .name = "PWM1_CLK", .rate_hz = &fixedrate, }, { .name = "PWM2_CLK", .rate_hz = &fixedrate, }, { .name = "PWM3_CLK", .rate_hz = &fixedrate, }, { .name = "USBCLK", .rate_hz = &fixedrate, }, { .name = "VOICECODEC_CLK", .rate_hz = &voicerate, }, { .name = "RTC_CLK", .rate_hz = &fixedrate, }, { .name = "KEYSCAN_CLK", .rate_hz = &fixedrate, }, { .name = "ADCIF_CLK", .rate_hz = &fixedrate, }, }; /* clocks cannot be de-registered no refcounting necessary */ struct clk *clk_get(const char *id) { struct clk *clk; rt_list_t *list; for (list = (&clocks)->next; list != &clocks; list = list->next) { clk = (struct clk *)rt_list_entry(list, struct clk, node); if (rt_strcmp(id, clk->name) == 0) return clk; } return RT_NULL; } rt_uint32_t clk_get_rate(struct clk *clk) { rt_uint32_t flags; rt_uint32_t *rate; for (;;) { rate = clk->rate_hz; if (rate || !clk->parent) break; clk = clk->parent; } return *rate; } void clk_register(struct clk *clk) { rt_list_insert_after(&clocks, &clk->node); } int davinci_register_clks(struct clk *clk_list, int num_clks) { struct clk *clkp; int i; for (i = 0, clkp = clk_list; i < num_clks; i++, clkp++) { //rt_kprintf("1:%s\n", clkp->name); clk_register(clkp); //rt_kprintf("2:%s\n", clkp->name); } return 0; } /* PLL/Reset register offsets */ #define PLLM 0x110 #define PREDIV 0x114 #define PLLDIV2 0x11C #define POSTDIV 0x128 #define PLLDIV4 0x160 #define PLLDIV5 0x164 #define PLLDIV6 0x168 #define PLLDIV7 0x16C #define PLLDIV8 0x170 int davinci_clk_init(void) { struct clk *clk_list; int num_clks; rt_uint32_t pll0_mult, pll1_mult; unsigned long prediv, postdiv; unsigned long pll_rate; unsigned long pll_div2, pll_div4, pll_div5, pll_div6, pll_div7, pll_div8; rt_list_init(&clocks); //davinci_psc_register(davinci_psc_base, 1); pll0_mult = davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLM); pll1_mult = davinci_readl(DAVINCI_PLL_CNTRL1_BASE + PLLM); commonrate = ((pll0_mult + 1) * 27000000) / 6; armrate = ((pll0_mult + 1) * 27000000) / 2; fixedrate = 24000000; /* Read PLL0 configuration */ prediv = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PREDIV) & 0x1f) + 1; postdiv = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + POSTDIV) & 0x1f) + 1; /* PLL0 dividers */ pll_div4 = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLDIV4) & 0x1f) + 1; /* EDMA, EMAC, config, common */ pll_div5 = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLDIV5) & 0x1f) + 1; /* VPSS */ pll_div6 = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLDIV6) & 0x1f) + 1; /* VENC */ pll_div7 = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLDIV7) & 0x1f) + 1; /* DDR */ pll_div8 = (davinci_readl(DAVINCI_PLL_CNTRL0_BASE + PLLDIV8) & 0x1f) + 1; /* MMC/SD */ pll_rate = ((fixedrate / prediv) * (2 * pll0_mult)) / postdiv; commonrate = pll_rate / pll_div4; /* 486/4 = 121.5MHz */ vpssrate = pll_rate / pll_div5; /* 486/2 = 243MHz */ vencrate_sd = pll_rate / pll_div6; /* 486/18 = 27MHz */ ddrrate = pll_rate / pll_div7; /* 486/2 = 243MHz */ mmcsdrate = pll_rate / pll_div8; /* 486/4 = 121.5MHz */ rt_kprintf( "PLL0: fixedrate: %d, commonrate: %d, vpssrate: %d\n", fixedrate, commonrate, vpssrate); rt_kprintf( "PLL0: vencrate_sd: %d, ddrrate: %d mmcsdrate: %d\n", vencrate_sd, (ddrrate/2), mmcsdrate); /* Read PLL1 configuration */ prediv = (davinci_readl(DAVINCI_PLL_CNTRL1_BASE + PREDIV) & 0x1f) + 1; postdiv = (davinci_readl(DAVINCI_PLL_CNTRL1_BASE + POSTDIV) & 0x1f) + 1; pll_rate = ((fixedrate / prediv) * (2 * pll1_mult)) / postdiv; /* PLL1 dividers */ pll_div2 = (davinci_readl(DAVINCI_PLL_CNTRL1_BASE + PLLDIV2) & 0x1f) + 1; /* ARM */ pll_div4 = (davinci_readl(DAVINCI_PLL_CNTRL1_BASE + PLLDIV4) & 0x1f) + 1; /* VOICE */ pll_div5 = (davinci_readl(DAVINCI_PLL_CNTRL1_BASE + PLLDIV5) & 0x1f) + 1; /* VENC */ armrate = pll_rate / pll_div2; /* 594/2 = 297MHz */ voicerate = pll_rate / pll_div4; /* 594/6 = 99MHz */ vencrate_hd = pll_rate / pll_div5; /* 594/8 = 74.25MHz */ rt_kprintf( "PLL1: armrate: %d, voicerate: %d, vencrate_hd: %d\n", armrate, voicerate, vencrate_hd); clk_list = davinci_dm365_clks; num_clks = ARRAY_SIZE(davinci_dm365_clks); return davinci_register_clks(clk_list, num_clks); } void platform_init(void) { edma_init(dm365_edma_info); } /* Reset board using the watchdog timer */ void reset_system(void) { rt_uint32_t tgcr, wdtcr; rt_uint32_t base = DAVINCI_WDOG_BASE; /* Disable, internal clock source */ davinci_writel(0, base + TCR); /* Reset timer, set mode to 64-bit watchdog, and unreset */ davinci_writel(0, base + TGCR); tgcr = (TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT) | (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); davinci_writel(tgcr, base + TGCR); /* Clear counter and period regs */ davinci_writel(0, base + TIM12); davinci_writel(0, base + TIM34); davinci_writel(0, base + PRD12); davinci_writel(0, base + PRD34); /* Enable periodic mode */ davinci_writel(TCR_ENAMODE_PERIODIC << ENAMODE12_SHIFT, base + TCR); /* Put watchdog in pre-active state */ wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) | (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); davinci_writel(wdtcr, base + WDTCR); /* Put watchdog in active state */ wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) | (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); davinci_writel(wdtcr, base + WDTCR); /* * Write an invalid value to the WDKEY field to trigger * a watchdog reset. */ wdtcr = 0xDEADBEEF; davinci_writel(wdtcr, base + WDTCR); }