www.pudn.com > mizi_vivi.rar > cpu.c
/* * Copyright (C) 2001 MIZI Research, Inc. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * History * * 2002-02-23: Janghoon Lyu* - Initial code */ #include "config.h" #include "bootconfig.h" #include "command-lib.h" #include "s3c2400.h" #include static void command_info(int argc, const char **argv); static void command_clock(int argc, const char **argv); static void cpu_usage(void); static struct bootblk_command cpu_commands[] = { { "info", command_info, "cpu info" }, { "clock", command_clock, "cpu clock " }, { NULL, NULL, NULL } }; void command_cpu(int argc, const char **argv) { if (argc == 1) { putstr("invalid 'cpu' command: too few arguments\r\n"); cpu_usage(); } else { execcmd(cpu_commands, argc - 1, argv + 1); } } static inline void print_clock(char *name, unsigned long clock) { char vbuf[32]; u32todecimal(vbuf, clock); putstr(name); putstr(": "); putstr(vbuf); u32todecimal(vbuf, (clock/1000000)); putstr(" ("); putstr(vbuf); putstr(" Mhz)\r\n"); } static void command_info(int argc, const char **argv) { long armrev = 0; unsigned long tmp; unsigned long fclk, mdiv, pdiv, sdiv; char vbuf[32]; tmp = _MPLLCON; mdiv = gPLLCON_MDIV(tmp); pdiv = gPLLCON_PDIV(tmp); sdiv = gPLLCON_SDIV(tmp); fclk = (((mdiv + 8) * FIN) / ((pdiv + 2) * (1 << sdiv))); __asm__("mrc p15, 0, %0, c0, c0, 0" : "=r" (armrev)); putstr("CPU INFORMATION\r\n"); putLabeledWord(" Revision Number: 0x", armrev); print_clock(" FCLK (cpu clock):", fclk); putstr(" MDIV: 0x"); putHexInt32(mdiv); putstr(" PDIV: 0x"); putHexInt32(pdiv); putLabeledWord(" SDIV: 0x", sdiv); tmp = _CLKDIVN; putstr(" Bus clock\r\n"); if (tmp == 0) { print_clock(" HCLK", fclk); print_clock(" PCLK", fclk); } else if (tmp == 1) { print_clock(" HCLK", fclk); print_clock(" PCLK", fclk/2); } else if (tmp == 2) { print_clock(" HCLK", fclk/2); print_clock(" PCLK", fclk/2); } else if (tmp == 3) { print_clock(" HCLK", fclk/2); print_clock(" PCLK", fclk/4); } } struct clock_div { unsigned long clock; unsigned long mdiv; unsigned long pdiv; unsigned long sdiv; }; /* If Fin is 12Mhz */ struct clock_div s3c2400_clocks[] = { /*{ mdiv, sdiv, pdiv}, */ { 33, 0x7c, 0x4, 0x3 }, { 50, 0x5c, 0x4, 0x2 }, { 66, 0x3a, 0x4, 0x1 }, { 70, 0x3e, 0x4, 0x1 }, { 75, 0x8e, 0x4, 0x2 }, /*{ 75, 0x43, 0x4, 0x1 }, */ { 80, 0x98, 0x4, 0x2 }, { 100, 0x5c, 0x4, 0x1 }, { 133, 0x7d, 0x4, 0x1 }, { 140, 0x84, 0x4, 0x1 }, { 150, 0x8e, 0x4, 0x1 }, { 170, 0xa2, 0x4, 0x1 }, { 180, 0x52, 0x4, 0x0 }, { 200, 0x5c, 0x4, 0x0 }, { 220, 0x56, 0x5, 0x0 }, { 0, 0, 0, 0 } }; /* Unit of clock is hertz */ static void reinit_baudrate(unsigned long clock) { unsigned long baudrate; unsigned long ubrdiv; get_param_value("baudrate", &baudrate); ubrdiv = ((clock / (baudrate * 16)) - 1); #if defined(CONFIG_SERIAL_UART0) CTL_REG_WRITE(UBRDIV0, ubrdiv); #elif defined(CONFIG_SERIAL_UART1) CTL_REG_WRITE(UBRDIV1, ubrdiv); #endif } /* Unit of clcok is mega hertz */ static void set_clock(unsigned long new_clock, unsigned long ratio) { int index; unsigned long mpll = 0; unsigned long mdiv, pdiv, sdiv; struct clock_div *clocks = s3c2400_clocks; if (ratio > 3) { putstr(" invalid arguments: ratio value is 0, 1, 2, 3\r\n"); return; } while (clocks->clock != 0) { if (new_clock == clocks->clock) break; clocks++; } if (clocks->clock == 0) { putstr(" couldn't find cpu clock\r\n"); return; } mdiv = clocks->mdiv; pdiv = clocks->pdiv; sdiv = clocks->sdiv; mpll = ((mdiv << 12) | (pdiv << 4) | (sdiv)); _MPLLCON = mpll; _CLKDIVN = ratio; init_mem_regs(); if (ratio == 0) { reinit_baudrate((new_clock * 1000000)); } else if ((ratio == 1) || (ratio == 2)) { reinit_baudrate((new_clock * 1000000) / 2); } else { reinit_baudrate((new_clock * 1000000) / 4); } } static void command_clock(int argc, const char **argv) { if (argc < 3) { putstr("invalid 'cpu' command: too few arguments\r\n"); cpu_usage(); return; } else if (argc > 3) { putstr("invalid 'cpu' command: too many arguments\r\n"); cpu_usage(); return; } set_clock(strtoul(argv[1], NULL, 0, NULL), strtoul(argv[2], NULL, 0, NULL)); } static void cpu_usage(void) { print_usage(" ", cpu_commands); }