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:
parent
367aec35d7
commit
be0c7d0ff3
6 changed files with 173 additions and 111 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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++;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue