| #include "tests.h" |
| #include <diags.h> |
| #include <init.h> |
| #include "slic.h" |
| #include <asm/types.h> |
| #include <common.h> |
| #include <asm/io.h> |
| #include <asm/system.h> |
| #include <asm-generic/div64.h> |
| |
| #include <mach/gpio.h> |
| #include <mach/comcerto-2000.h> |
| #include <mach/clkcore.h> |
| |
| extern int legerity_init(void); |
| |
| static inline void delay(volatile u32 delay_count) |
| { |
| while(delay_count--); |
| } |
| |
| #define TDMNTG_REG_RST (1 << 0) |
| #define FSYNC_FALL_EDGE (1 << 1) |
| #define NTG_DIV_RST_N (1 << 5) |
| #define NTG_EN (1 << 0) |
| |
| #define TDMNTG_ADDR_SPACE_BASEADDR (COMCERTO_APB_CLK_BASE + 0x280) |
| #define TDM_NTG_CLK_CTRL (TDMNTG_ADDR_SPACE_BASEADDR + 0x00) |
| #define TDM_NTG_INCR (TDMNTG_ADDR_SPACE_BASEADDR + 0x04) |
| #define TDM_FSYNC_GEN_CTRL (TDMNTG_ADDR_SPACE_BASEADDR + 0x08) |
| #define TDM_FSYNC_LOW (TDMNTG_ADDR_SPACE_BASEADDR + 0x0C) |
| #define TDM_FSYNC_HIGH (TDMNTG_ADDR_SPACE_BASEADDR + 0x10) |
| |
| #define TDMNTG_DEFAULT_REF_CLK 500000000 |
| #define PLL_SOURCE_TDM_CLK PLL2 |
| |
| /* TDM Divider value to 24 */ |
| #define NTG_TDM_CLK_DIV 24 |
| |
| unsigned long tdmntg_ref_clk; |
| |
| /* since 'ppm' means parts-per-million */ |
| #define MILLION (1000000UL) |
| |
| static unsigned long BaseClock = 0; /* frequency is set by clock_frequency_set() */ |
| |
| struct comcerto_tdm_data { |
| u8 fsoutput; /* Generic Pad Control and Version ID Register[2] */ |
| u8 fspolarity; /* 28 FSYNC_FALL(RISE)_EDGE */ |
| u16 fshwidth; /* High_Phase_Width[10:0] */ |
| u16 fslwidth; /* Low_Phase_Width[26:16]] */ |
| u32 clockhz; /* INC_VALUE[29:0] According to the desired TDM clock output frequency, this field should be configured */ |
| u8 clockout; /* IO Control Register[21] hardware or software control selection IO Control Register[20] pads are input (output) */ |
| u8 tdmmux; |
| u32 tdmck; |
| u32 tdmfs; |
| u32 tdmdx; |
| u32 tdmdr; |
| }; |
| |
| //Legerity |
| static struct comcerto_tdm_data comcerto_tdm_pdata = { |
| .fsoutput = 1, /* Generic Pad Control and Version ID Register[2] */ |
| .fspolarity = 0, /* 28 FSYNC_FALL(RISE)_EDGE */ |
| .fshwidth = 1, /* High_Phase_Width[10:0] */ |
| .fslwidth = 0xFF, /* Low_Phase_Width[10:0] */ |
| .clockhz = 2048000, /* INC_VALUE[29:0] According to the desired TDM clock output frequency, this field should be configured */ |
| .clockout = 1, /* 0 -> set bit 21, clear bit 20 in COMCERTO_GPIO_IOCTRL_REG |
| (software control, clock input) |
| 1 -> set bit 21 and 20 in COMCERTO_GPIO_IOCTRL_REG |
| (software control, clock output) |
| 2 -> clear bit 21 in COMCERTO_GPIO_IOCTRL_REG (hardware control) */ |
| /* TDM interface Muxing:0x0 - TDM block, 0x1 - ZDS block, |
| 0x2 - GPIO[63:60] signals and 0x3 - MSIF block is selected */ |
| .tdmmux = 0x1, |
| #if 0 |
| .tdmck = 0x11, //0x3F, |
| .tdmfs = 0x11, //0x3F, |
| .tdmdx = 0x11, //0x3F, |
| .tdmdr = 0x11, //0x3F, |
| #endif |
| }; |
| |
| |
| static void fsync_output_set(unsigned int fsoutput) |
| { |
| if (fsoutput) |
| { |
| writel(readl(COMCERTO_GPIO_TDM_MUX) | (1 << 0), COMCERTO_GPIO_TDM_MUX); |
| writel(readl(TDM_FSYNC_GEN_CTRL) | (1 << 0), TDM_FSYNC_GEN_CTRL); |
| } |
| else |
| { |
| writel(readl(COMCERTO_GPIO_TDM_MUX) & ~(1 << 0), COMCERTO_GPIO_TDM_MUX); |
| writel(readl(TDM_FSYNC_GEN_CTRL) & ~(1 << 0), TDM_FSYNC_GEN_CTRL); |
| } |
| } |
| |
| static void fsync_polarity_set(unsigned int fspolarity) |
| { |
| /* 28 FSYNC_FALL(RISE)_EDGE */ |
| if (fspolarity) |
| writel(readl(TDM_FSYNC_GEN_CTRL) | FSYNC_FALL_EDGE, TDM_FSYNC_GEN_CTRL); |
| else |
| writel(readl(TDM_FSYNC_GEN_CTRL) & ~FSYNC_FALL_EDGE, TDM_FSYNC_GEN_CTRL); |
| } |
| |
| static void fsync_lphase_set(u32 fslwidth) |
| { |
| /* Low_Phase_Width 7ff- maximum */ |
| if (fslwidth > 0x7FF) { |
| printf("%s: Low Phase width value is out of range %#x > 0x7FF", __func__, fslwidth); |
| return; |
| } |
| |
| writel(fslwidth, TDM_FSYNC_LOW); |
| } |
| |
| static void fsync_hphase_set(u32 fshwidth) |
| { |
| /* High_Phase_Width 7ff- maximum */ |
| if (fshwidth > 0x7FF) { |
| printf("%s: High Phase width value is out of range %#x > 0x7FF", __func__, fshwidth); |
| return; |
| } |
| |
| writel(fshwidth, TDM_FSYNC_HIGH); |
| } |
| |
| static void clock_frequency_set(unsigned long clockhz) |
| { |
| unsigned long long ntg_incr; // = clockhz; |
| |
| /* Multiply with NTG_TDM_CLK_DIV(24) */ |
| ntg_incr = NTG_TDM_CLK_DIV * clockhz; |
| |
| /* get frequency resolution on an 32-bit accumulator */ |
| ntg_incr = ntg_incr * (1ULL << 32) + tdmntg_ref_clk / 2; |
| do_div(ntg_incr, tdmntg_ref_clk); |
| printf("%s: NTG INCR value is 0x%x\n", __func__, ntg_incr); |
| |
| /* ntg_incr = 0x192A7371 for 49.152 MHz */ |
| writel(ntg_incr, TDM_NTG_INCR); |
| } |
| |
| static unsigned long clock_frequency_get(void) |
| { |
| unsigned long long clc_data; |
| |
| /* According to the desired TDM clock output frequency, this field should be configured */ |
| clc_data = (readl(TDM_NTG_INCR) & 0x3FFFFFFF);/* get frequency from resolution on an 32-bit accumulator */ |
| clc_data = (clc_data * tdmntg_ref_clk + (1ULL << 31)) >> 32; |
| return (unsigned long)clc_data; |
| } |
| |
| |
| static void clock_output_set(unsigned long clockout) |
| { |
| switch (clockout) { |
| case 0: |
| writel((0x2 << 12) | (readl(COMCERTO_GPIO_BOOTSTRAP_OVERRIDE) & ~(0x3 << 12)), COMCERTO_GPIO_BOOTSTRAP_OVERRIDE); |
| break; |
| case 1: |
| writel((0x3 << 12) | (readl(COMCERTO_GPIO_BOOTSTRAP_OVERRIDE) & ~(0x3 << 12)), COMCERTO_GPIO_BOOTSTRAP_OVERRIDE); |
| break; |
| case 2: |
| writel((0x0 << 12) | (readl(COMCERTO_GPIO_BOOTSTRAP_OVERRIDE) & ~(0x3 << 12)), COMCERTO_GPIO_BOOTSTRAP_OVERRIDE); |
| break; |
| default: |
| printf("%s: Unknown clock output value\n", __func__); |
| } |
| } |
| |
| static void clock_ppm_adjust(long ppm) |
| { |
| unsigned long long clc_data; |
| unsigned long freq_set = BaseClock; |
| int nsign = 0; |
| |
| if (!freq_set) { |
| printf("(%s): Could not adjust frequency: you should set it before\n", __func__); |
| return; |
| } |
| |
| if (ppm < 0) { |
| nsign = 1; |
| ppm = -ppm; |
| } |
| |
| if (nsign && (ppm >= MILLION)) { |
| /* overflow dangerous */ |
| printf("(%s): This is too much ppm: -%lu\n", __func__, (unsigned long)ppm); |
| return; |
| } |
| |
| clc_data = ppm * (1ULL << 32); |
| |
| do_div(clc_data, MILLION); |
| |
| if (nsign) { |
| clc_data = (1ULL << 32) - clc_data; |
| } else { |
| clc_data = (1ULL << 32) + clc_data; |
| } |
| |
| clc_data = clc_data * freq_set + tdmntg_ref_clk / 2; /* with rounding to nearest integer */ |
| |
| if (clc_data & ~0x3FFFFFFF) { |
| /* unaccounted bits dangerous */ |
| printf("(%s): This is too much ppm: %lu\n", __func__, (unsigned long)ppm); |
| return; |
| } |
| |
| writel((clc_data & 0x3FFFFFFF) | (readl(TDM_NTG_INCR) & ~0x3FFFFFFF), TDM_NTG_INCR); |
| } |
| |
| static long clock_ppm_get(void) |
| { |
| unsigned long freq_set = BaseClock; |
| unsigned long freq = clock_frequency_get(); |
| unsigned long long ppm; |
| |
| if (freq > freq_set) { |
| ppm = (freq - freq_set) * MILLION + (freq_set >> 1); |
| do_div(ppm, freq_set); |
| return (long)ppm; |
| } else { |
| ppm = (freq_set - freq) * MILLION + (freq_set >> 1); |
| do_div(ppm, freq_set); |
| return (-1 * (long)ppm); |
| } |
| } |
| |
| static void tdm_mux_set(u32 tdmmux) |
| { |
| switch (tdmmux){ |
| case 0: |
| // TDM block selected |
| writel((0x0 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT_REG) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT_REG); |
| break; |
| |
| case 1: |
| // ZDS (Zarlink) block selected |
| writel((0x1 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT_REG) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT_REG); |
| break; |
| |
| case 2: |
| // GPIO[63:60] signals selected |
| writel((0x2 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT_REG) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT_REG); |
| break; |
| |
| case 3: |
| // MSIF (SiLabs) selected |
| writel((0x3 << 4) |(readl(COMCERTO_GPIO_MISC_PIN_SELECT_REG) & ~(0x3 << 4)), COMCERTO_GPIO_MISC_PIN_SELECT_REG); |
| break; |
| |
| default: |
| printf("%s: Unknown TDM MUX value\n", __func__); |
| } |
| } |
| |
| static void tdm_dr_set(u32 tdmdr) |
| { |
| if(tdmdr > 0x3F) |
| { |
| printf("%s: TDM_DR value is out of range %#x > 0x3F", __func__, tdmdr); |
| return; |
| } |
| |
| writel((tdmdr << 24) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 24)), COMCERTO_GPIO_PAD_CONFIG0); |
| } |
| |
| static void tdm_dx_set(u32 tdmdx) |
| { |
| if(tdmdx > 0x3F) |
| { |
| printf("%s: TDM_DX value is out of range %#x > 0x3F", __func__, tdmdx); |
| return; |
| } |
| |
| writel((tdmdx << 18) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 18)), COMCERTO_GPIO_PAD_CONFIG0); |
| } |
| |
| static void tdm_fs_set(u32 tdmfs) |
| { |
| if(tdmfs > 0x3F) |
| { |
| printf("%s: TDM_FS value is out of range %#x > 0x3F", __func__, tdmfs); |
| return; |
| } |
| |
| writel((tdmfs << 12) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 12)), COMCERTO_GPIO_PAD_CONFIG0); |
| } |
| |
| static void tdm_ck_set(u32 tdmck) |
| { |
| if(tdmck > 0x3F) |
| { |
| printf("%s: TDM_CK value is out of range %#x > 0x3F", __func__, tdmck); |
| return; |
| } |
| |
| writel((tdmck << 6) |(readl(COMCERTO_GPIO_PAD_CONFIG0) & ~(0x3F << 6)), COMCERTO_GPIO_PAD_CONFIG0); |
| } |
| |
| void c2k_zds_init(void) |
| { |
| tdmntg_ref_clk = TDMNTG_DEFAULT_REF_CLK; |
| |
| printf("Initializing ZDS/NTG..\n"); |
| |
| // Take TDM NTG out of reset |
| writel(readl(TDMNTG_RESET) & ~TDMNTG_REG_RST, TDMNTG_RESET); |
| |
| switch(PLL_SOURCE_TDM_CLK) |
| { |
| case PLL0: |
| writel(readl(TDMNTG_REF_CLK_CNTRL) | ((1 << 0) | (1 << 0)), TDMNTG_REF_CLK_CNTRL); |
| break; |
| |
| case PLL1: |
| writel(readl(TDMNTG_REF_CLK_CNTRL) | ((1 << 1) | (1 << 0)), TDMNTG_REF_CLK_CNTRL); |
| break; |
| |
| case PLL3: |
| writel(readl(TDMNTG_REF_CLK_CNTRL) | ((1 << 3) | (1 << 0)), TDMNTG_REF_CLK_CNTRL); |
| break; |
| |
| case PLL2: |
| default: |
| writel(readl(TDMNTG_REF_CLK_CNTRL) | ((1 << 2) | (1 << 0)), TDMNTG_REF_CLK_CNTRL); |
| break; |
| } |
| |
| // NTG REF CLK is derived from PLL2 |
| writel(0x3, TDMNTG_REF_CLK_DIV_CNTRL); |
| writel((NTG_DIV_RST_N | NTG_EN), TDM_NTG_CLK_CTRL); |
| writel(0x80, TDM_CLK_CNTRL); /* NTG = 24 x TDM */ |
| |
| /* Inital configuration of tdm bus */ |
| fsync_polarity_set(comcerto_tdm_pdata.fspolarity); |
| fsync_lphase_set(comcerto_tdm_pdata.fslwidth); |
| fsync_hphase_set(comcerto_tdm_pdata.fshwidth); |
| clock_frequency_set(comcerto_tdm_pdata.clockhz); |
| clock_output_set(comcerto_tdm_pdata.clockout); |
| fsync_output_set(comcerto_tdm_pdata.fsoutput); |
| tdm_mux_set(comcerto_tdm_pdata.tdmmux); |
| #if 0 |
| // The default paramters are good |
| tdm_dr_set(comcerto_tdm_pdata.tdmdr); |
| tdm_dx_set(comcerto_tdm_pdata.tdmdx); |
| tdm_fs_set(comcerto_tdm_pdata.tdmfs); |
| tdm_ck_set(comcerto_tdm_pdata.tdmck); |
| #endif |
| writel(0x18, TDM_CLK_CNTRL); //remove out of reset |
| |
| #define COMCERTO_GPIO1_OUTPUT_REG ((COMCERTO_APB_GPIO_BASE + 0xd0)) |
| writel(0x1 << 30, COMCERTO_GPIO1_OUTPUT_REG); |
| |
| } |
| |
| int Comcerto_zds_slic_test (struct diags_test_param *p) |
| { |
| int ret = 0; |
| |
| c2k_zds_init(); |
| ret = legerity_init(); |
| if(ret) |
| return -1; |
| |
| return 0; |
| } |
| |