1
0
Fork 0
forked from len0rd/rockbox

Gigabeat S: Use the fastest PIO mode the installed drive allows instead of always PIO0. Centralize clock information in clkctl-imx31.c.

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17371 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Michael Sevakis 2008-05-05 10:53:06 +00:00
parent 367aec35d7
commit be0c7d0ff3
6 changed files with 173 additions and 111 deletions

View file

@ -1089,6 +1089,10 @@ static int identify(void)
identify_info[i] = ATA_DATA;
#endif
}
#ifdef ATA_NOTIFY_IDENTIFY_READY
ata_identify_ready();
#endif
return 0;
}

View file

@ -26,32 +26,7 @@
#include "debug-target.h"
#include "mc13783.h"
#include "adc.h"
#define CONFIG_CLK32_FREQ 32768
#define CONFIG_HCLK_FREQ 27000000
/* Return PLL frequency in HZ */
static unsigned int decode_pll(unsigned int reg,
unsigned int infreq)
{
uint64_t mfi = (reg >> 10) & 0xf;
uint64_t mfn = reg & 0x3ff;
uint64_t mfd = ((reg >> 16) & 0x3ff) + 1;
uint64_t pd = ((reg >> 26) & 0xf) + 1;
mfi = mfi <= 5 ? 5 : mfi;
return 2*infreq*(mfi * mfd + mfn) / (mfd * pd);
}
/* Get the PLL reference clock frequency */
static unsigned int get_pll_ref_clk_freq(void)
{
if ((CLKCTL_CCMR & (3 << 1)) == (1 << 1))
return CONFIG_CLK32_FREQ * 1024;
else
return CONFIG_HCLK_FREQ;
}
#include "clkctl-imx31.h"
bool __dbg_hw_info(void)
{
@ -74,11 +49,11 @@ bool __dbg_hw_info(void)
spctl = CLKCTL_SPCTL;
upctl = CLKCTL_UPCTL;
pllref = get_pll_ref_clk_freq();
pllref = imx31_clkctl_get_pll_ref_clk();
mcu_pllfreq = decode_pll(mpctl, pllref);
ser_pllfreq = decode_pll(spctl, pllref);
usb_pllfreq = decode_pll(upctl, pllref);
mcu_pllfreq = imx31_clkctl_get_pll(PLL_MCU);
ser_pllfreq = imx31_clkctl_get_pll(PLL_SERIAL);
usb_pllfreq = imx31_clkctl_get_pll(PLL_USB);
snprintf(buf, sizeof (buf), "pll_ref_clk: %u", pllref);
lcd_puts(0, line++, buf); line++;

View file

@ -23,8 +23,82 @@
#include "system.h"
#include "power.h"
#include "panic.h"
#include "pcf50606.h"
#include "ata-target.h"
#include "ata.h"
#include "clkctl-imx31.h"
static const struct ata_pio_timings
{
uint16_t time_2w; /* t2 during write */
uint16_t time_2r; /* t2 during read */
uint8_t time_1; /* t1 */
uint8_t time_pio_rdx; /* trd */
uint8_t time_4; /* t4 */
uint8_t time_9; /* t9 */
} pio_timings[5] =
{
[0] = /* PIO mode 0 */
{
.time_1 = 70,
.time_2w = 290,
.time_2r = 290,
.time_4 = 30,
.time_9 = 20
},
[1] = /* PIO mode 1 */
{
.time_1 = 50,
.time_2w = 290,
.time_2r = 290,
.time_4 = 20,
.time_9 = 15
},
[2] = /* PIO mode 2 */
{
.time_1 = 30,
.time_2w = 290,
.time_2r = 290,
.time_4 = 15,
.time_9 = 10
},
[3] = /* PIO mode 3 */
{
.time_1 = 30,
.time_2w = 80,
.time_2r = 80,
.time_4 = 10,
.time_9 = 10
},
[4] = /* PIO mode 4 */
{
.time_1 = 25,
.time_2w = 70,
.time_2r = 70,
.time_4 = 10,
.time_9 = 10
},
};
/* Setup the timing for PIO mode */
static void ata_set_pio_mode(int mode)
{
const struct ata_pio_timings * const timings = &pio_timings[mode];
/* T = period in nanoseconds */
int T = 1000 * 1000 * 1000 / imx31_clkctl_get_ata_clk();
while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE));
ATA_TIME_OFF = 3;
ATA_TIME_ON = 3;
ATA_TIME_1 = (timings->time_1 + T) / T;
ATA_TIME_2W = (timings->time_2w + T) / T;
ATA_TIME_2R = (timings->time_2r + T) / T;
ATA_TIME_AX = (35 + T) / T; /* tA */
ATA_TIME_PIO_RDX = 1;
ATA_TIME_4 = (timings->time_4 + T) / T;
ATA_TIME_9 = (timings->time_9 + T) / T;
}
void ata_reset(void)
{
@ -47,92 +121,35 @@ bool ata_is_coldstart(void)
return true;
}
unsigned long get_pll(bool serial) {
unsigned long mfi, mfn, mfd, pdf, ref_clk;
unsigned long reg = 0, ccmr;
unsigned long long temp;
unsigned int prcs;
ccmr = CLKCTL_CCMR;
prcs = (ccmr & 0x6) >> 1;
if(prcs == 0x1) {
ref_clk = 32768 * 1024;
} else {
ref_clk = 27000000;
}
if(serial) {
reg = CLKCTL_SPCTL;
} else {
if((ccmr & 0x8) == 0)
return ref_clk;
if((ccmr & 0x80) != 0)
return ref_clk;
reg = CLKCTL_MPCTL;
}
pdf = (reg & (0x7 << 26)) >> 26;
mfd = (reg & (0x3FF << 16)) >> 16;
mfi = (reg & (0xF << 10)) >> 10;
mfi = (mfi <= 5) ? 5 : mfi;
mfn = (reg & 0x3FF);
if(mfn < 0x200) {
temp = (unsigned long long)2 *ref_clk * mfn;
temp /= (mfd + 1);
temp = (unsigned long long)2 *ref_clk * mfi + temp;
temp /= (pdf + 1);
} else {
temp = (unsigned long long)2 *ref_clk * (0x400 - mfn);
temp /= (mfd + 1);
temp = (unsigned long long)2 *ref_clk * mfi - temp;
temp /= (pdf + 1);
}
return (unsigned long)temp;
}
unsigned long get_ata_clock(void) {
unsigned long pll, ret_val, hclk, max_pdf, ipg_pdf, mcu_pdf;
max_pdf = (CLKCTL_PDR0 & (0x7 << 3)) >> 3;
ipg_pdf = (CLKCTL_PDR0 & (0x3 << 6)) >> 6;
mcu_pdf = (CLKCTL_PDR0 & 0x7);
if((CLKCTL_PMCR0 & 0xC0000000 ) == 0) {
pll = get_pll(true);
} else {
pll = get_pll(false);
}
hclk = pll/(max_pdf + 1);
ret_val = hclk / (ipg_pdf + 1);
return ret_val;
}
void ata_device_init(void)
{
ATA_INTF_CONTROL |= ATA_ATA_RST; /* Make sure we're not in reset mode */
while (!(ATA_INTERRUPT_PENDING & ATA_CONTROLLER_IDLE));
/* Setup the timing for PIO mode */
int T = 1000 * 1000 * 1000 / get_ata_clock();
ATA_TIME_OFF = 3;
ATA_TIME_ON = 3;
ATA_TIME_1 = (T + 70)/T;
ATA_TIME_2W = (T + 290)/T;
ATA_TIME_2R = (T + 290)/T;
ATA_TIME_AX = (T + 50)/T;
ATA_TIME_PIO_RDX = 1;
ATA_TIME_4 = (T + 30)/T;
ATA_TIME_9 = (T + 20)/T;
/* Setup mode 0 by default */
ata_set_pio_mode(0);
}
#if 0
#if !defined(BOOTLOADER)
void copy_write_sectors(const unsigned char* buf, int wordcount)
void ata_identify_ready(void)
{
(void)buf; (void)wordcount;
const unsigned short* identify_info = ata_get_identify();
int mode = 0;
if (identify_info[53] & (1 << 1))
{
/* Set up advanced timings */
if (identify_info[64] & (1 << 1))
mode = 4; /* Mode 0, 1, 2, 3, 4 */
else if (identify_info[64] & (1 << 0))
mode = 3; /* Mode 0, 1, 2, 3 */
else
mode = 2; /* Mode 0, 1, 2 */
}
/* If mode changed, actually set the timings */
if (mode != 0)
{
ata_set_pio_mode(mode);
}
}
#endif
#endif

View file

@ -68,4 +68,7 @@ void ata_reset(void);
void ata_device_init(void);
bool ata_is_coldstart(void);
#define ATA_NOTIFY_IDENTIFY_READY
void ata_identify_ready(void);
#endif

View file

@ -43,3 +43,43 @@ void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg,
restore_interrupt(oldlevel);
}
/* Get the PLL reference clock frequency in HZ */
unsigned int imx31_clkctl_get_pll_ref_clk(void)
{
if ((CLKCTL_CCMR & (3 << 1)) == (1 << 1))
return CONFIG_CLK32_FREQ * 1024;
else
return CONFIG_HCLK_FREQ;
}
/* Return PLL frequency in HZ */
unsigned int imx31_clkctl_get_pll(enum IMX31_PLLS pll)
{
uint32_t infreq = imx31_clkctl_get_pll_ref_clk();
uint32_t reg = (&CLKCTL_MPCTL)[pll];
uint32_t mfn = reg & 0x3ff;
uint32_t pd = ((reg >> 26) & 0xf) + 1;
uint64_t mfd = ((reg >> 16) & 0x3ff) + 1;
uint32_t mfi = (reg >> 10) & 0xf;
mfi = mfi <= 5 ? 5 : mfi;
return 2*infreq*(mfi * mfd + mfn) / (mfd * pd);
}
unsigned int imx31_clkctl_get_ipg_clk(void)
{
unsigned int pll = imx31_clkctl_get_pll((CLKCTL_PMCR0 & 0xC0000000) == 0 ?
PLL_SERIAL : PLL_MCU);
uint32_t reg = CLKCTL_PDR0;
unsigned int max_pdf = ((reg >> 3) & 0x7) + 1;
unsigned int ipg_pdf = ((reg >> 6) & 0x3) + 1;
return pll / (max_pdf * ipg_pdf);
}
unsigned int imx31_clkctl_get_ata_clk(void)
{
return imx31_clkctl_get_ipg_clk();
}

View file

@ -83,4 +83,27 @@ enum IMX31_CG_MODES
void imx31_clkctl_module_clock_gating(enum IMX31_CG_LIST cg,
enum IMX31_CG_MODES mode);
enum IMX31_PLLS
{
PLL_MCU = 0,
PLL_USB,
PLL_SERIAL,
NUM_PLLS,
};
#define CONFIG_CLK32_FREQ 32768
#define CONFIG_HCLK_FREQ 27000000
/* Get the PLL reference clock frequency in HZ */
unsigned int imx31_clkctl_get_pll_ref_clk(void);
/* Return PLL frequency in HZ */
unsigned int imx31_clkctl_get_pll(enum IMX31_PLLS pll);
/* Return ipg_clk in HZ */
unsigned int imx31_clkctl_get_ipg_clk(void);
/* Return the ATA frequency in HZ */
unsigned int imx31_clkctl_get_ata_clk(void);
#endif /* _CLKCTL_IMX31_H_ */