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);
}