rt-thread-official/bsp/dm365/platform/dm365.c

370 lines
8.3 KiB
C

/*
* 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 <edma.h>
#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);
}
int platform_init(void)
{
edma_init(dm365_edma_info);
}
INIT_BOARD_EXPORT(platform_init);
/* 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);
}