From 2cf33133820ee17e4b5d2d622db15dedff1a1f6e Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Fri, 17 Jun 2011 22:30:58 +0000 Subject: fuze+: add more clocking code, add dma code, add ssp code, add stub usb code, update storage to SD + MMC, beginning of the driver git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30010 a1c6a512-1295-4272-9138-f99709370657 --- firmware/target/arm/imx233/clkctrl-imx233.c | 24 +++ firmware/target/arm/imx233/clkctrl-imx233.h | 16 ++ firmware/target/arm/imx233/dma-imx233.c | 133 ++++++++++++ firmware/target/arm/imx233/dma-imx233.h | 161 +++++++++++++++ firmware/target/arm/imx233/mmc-imx233.c | 100 +++++++++ firmware/target/arm/imx233/pinctrl-imx233.h | 16 ++ firmware/target/arm/imx233/sd-imx233.c | 14 ++ firmware/target/arm/imx233/ssp-imx233.c | 307 ++++++++++++++++++++++++++++ firmware/target/arm/imx233/ssp-imx233.h | 162 +++++++++++++++ firmware/target/arm/imx233/system-imx233.c | 12 ++ firmware/target/arm/imx233/system-target.h | 4 + firmware/target/arm/imx233/usb-imx233.c | 76 +++++++ 12 files changed, 1025 insertions(+) create mode 100644 firmware/target/arm/imx233/dma-imx233.c create mode 100644 firmware/target/arm/imx233/dma-imx233.h create mode 100644 firmware/target/arm/imx233/mmc-imx233.c create mode 100644 firmware/target/arm/imx233/ssp-imx233.c create mode 100644 firmware/target/arm/imx233/ssp-imx233.h create mode 100644 firmware/target/arm/imx233/usb-imx233.c (limited to 'firmware/target/arm') diff --git a/firmware/target/arm/imx233/clkctrl-imx233.c b/firmware/target/arm/imx233/clkctrl-imx233.c index 0b46a0e8db..7701b84c41 100644 --- a/firmware/target/arm/imx233/clkctrl-imx233.c +++ b/firmware/target/arm/imx233/clkctrl-imx233.c @@ -37,6 +37,7 @@ void imx233_enable_clock(enum imx233_clock_t clk, bool enable) switch(clk) { case CLK_PIX: REG = &HW_CLKCTRL_PIX; break; + case CLK_SSP: REG = &HW_CLKCTRL_SSP; break; default: return; } @@ -63,8 +64,30 @@ void imx233_set_clock_divisor(enum imx233_clock_t clk, int div) __REG_SET(HW_CLKCTRL_PIX) = div; while(HW_CLKCTRL_PIX & __CLK_BUSY); break; + case CLK_SSP: + __REG_CLR(HW_CLKCTRL_SSP) = (1 << 9) - 1; + __REG_SET(HW_CLKCTRL_SSP) = div; + while(HW_CLKCTRL_SSP & __CLK_BUSY); + break; + default: return; + } +} + +void imx233_set_fractional_divisor(enum imx233_clock_t clk, int fracdiv) +{ + /* NOTE: HW_CLKCTRL_FRAC only support byte access ! */ + volatile uint8_t *REG; + switch(clk) + { + case CLK_PIX: REG = &HW_CLKCTRL_FRAC_PIX; break; + case CLK_IO: REG = &HW_CLKCTRL_FRAC_IO; break; default: return; } + + if(fracdiv != 0) + *REG = fracdiv; + else + *REG = HW_CLKCTRL_FRAC_XX__CLKGATEXX;; } void imx233_set_bypass_pll(enum imx233_clock_t clk, bool bypass) @@ -73,6 +96,7 @@ void imx233_set_bypass_pll(enum imx233_clock_t clk, bool bypass) switch(clk) { case CLK_PIX: msk = HW_CLKCTRL_CLKSEQ__BYPASS_PIX; break; + case CLK_SSP: msk = HW_CLKCTRL_CLKSEQ__BYPASS_SSP; break; default: return; } diff --git a/firmware/target/arm/imx233/clkctrl-imx233.h b/firmware/target/arm/imx233/clkctrl-imx233.h index ffc15c1043..1533b52cce 100644 --- a/firmware/target/arm/imx233/clkctrl-imx233.h +++ b/firmware/target/arm/imx233/clkctrl-imx233.h @@ -31,9 +31,20 @@ #define HW_CLKCTRL_XTAL__TIMROT_CLK32K_GATE (1 << 26) #define HW_CLKCTRL_PIX (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x60)) +#define HW_CLKCTRL_SSP (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x70)) #define HW_CLKCTRL_CLKSEQ (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x110)) #define HW_CLKCTRL_CLKSEQ__BYPASS_PIX (1 << 1) +#define HW_CLKCTRL_CLKSEQ__BYPASS_SSP (1 << 5) + +#define HW_CLKCTRL_FRAC (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0xf0)) +#define HW_CLKCTRL_FRAC_CPU (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf0)) +#define HW_CLKCTRL_FRAC_EMI (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf1)) +#define HW_CLKCTRL_FRAC_PIX (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf2)) +#define HW_CLKCTRL_FRAC_IO (*(volatile uint8_t *)(HW_CLKCTRL_BASE + 0xf3)) +#define HW_CLKCTRL_FRAC_XX__XXDIV_BM 0x3f +#define HW_CLKCTRL_FRAC_XX__XX_STABLE (1 << 6) +#define HW_CLKCTRL_FRAC_XX__CLKGATEXX (1 << 7) #define HW_CLKCTRL_RESET (*(volatile uint32_t *)(HW_CLKCTRL_BASE + 0x120)) #define HW_CLKCTRL_RESET_CHIP 0x2 @@ -42,11 +53,16 @@ enum imx233_clock_t { CLK_PIX, + CLK_SSP, + CLK_IO, }; void imx233_enable_timrot_xtal_clk32k(bool enable); +/* only use it for non-fractional clocks (ie not for IO) */ void imx233_enable_clock(enum imx233_clock_t clk, bool enable); void imx233_set_clock_divisor(enum imx233_clock_t clk, int div); +/* call with fracdiv=0 to disable it */ +void imx233_set_fractional_divisor(enum imx233_clock_t clk, int fracdiv); void imx233_set_bypass_pll(enum imx233_clock_t clk, bool bypass); #endif /* CLKCTRL_IMX233_H */ diff --git a/firmware/target/arm/imx233/dma-imx233.c b/firmware/target/arm/imx233/dma-imx233.c new file mode 100644 index 0000000000..d75c334aeb --- /dev/null +++ b/firmware/target/arm/imx233/dma-imx233.c @@ -0,0 +1,133 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by amaury Pouly + * + * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing + * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "dma-imx233.h" + +void imx233_dma_init(void) +{ + /* Enable APHB and APBX */ + __REG_CLR(HW_APBH_CTRL0) = __BLOCK_CLKGATE | __BLOCK_SFTRST; + __REG_CLR(HW_APBX_CTRL0) = __BLOCK_CLKGATE | __BLOCK_SFTRST; +} + +void imx233_dma_reset_channel(unsigned chan) +{ + if(APB_IS_APBX_CHANNEL(chan)) + __REG_SET(HW_APBX_CHANNEL_CTRL) = + HW_APBX_CHANNEL_CTRL__RESET_CHANNEL(APB_GET_DMA_CHANNEL(chan)); + else + __REG_SET(HW_APBH_CTRL0) = + HW_APBH_CTRL0__RESET_CHANNEL(APB_GET_DMA_CHANNEL(chan)); +} + +void imx233_dma_clkgate_channel(unsigned chan, bool enable_clock) +{ + if(APB_IS_APBX_CHANNEL(chan)) + return; + if(enable_clock) + __REG_CLR(HW_APBH_CTRL0) = + HW_APBH_CTRL0__CLKGATE_CHANNEL(APB_GET_DMA_CHANNEL(chan)); + else + __REG_SET(HW_APBH_CTRL0) = + HW_APBH_CTRL0__CLKGATE_CHANNEL(APB_GET_DMA_CHANNEL(chan)); +} + +void imx233_dma_enable_channel_interrupt(unsigned chan, bool enable) +{ + volatile uint32_t *ptr; + uint32_t bm; + if(APB_IS_APBX_CHANNEL(chan)) + { + ptr = &HW_APBX_CTRL1; + bm = HW_APBX_CTRL1__CHx_CMDCMPLT_IRQ_EN(APB_GET_DMA_CHANNEL(chan)); + } + else + { + ptr = &HW_APBH_CTRL1;; + bm = HW_APBH_CTRL1__CHx_CMDCMPLT_IRQ_EN(APB_GET_DMA_CHANNEL(chan)); + } + + if(enable) + { + __REG_SET(*ptr) = bm; + imx233_dma_clear_channel_interrupt(chan); + } + else + __REG_CLR(*ptr) = bm; +} + +void imx233_dma_clear_channel_interrupt(unsigned chan) +{ + if(APB_IS_APBX_CHANNEL(chan)) + { + __REG_CLR(HW_APBX_CTRL1) = + HW_APBX_CTRL1__CHx_CMDCMPLT_IRQ(APB_GET_DMA_CHANNEL(chan)); + __REG_CLR(HW_APBX_CTRL2) = + HW_APBX_CTRL2__CHx_ERROR_IRQ(APB_GET_DMA_CHANNEL(chan)); + } + else + { + __REG_CLR(HW_APBH_CTRL1) = + HW_APBH_CTRL1__CHx_CMDCMPLT_IRQ(APB_GET_DMA_CHANNEL(chan)); + __REG_CLR(HW_APBH_CTRL2) = + HW_APBH_CTRL2__CHx_ERROR_IRQ(APB_GET_DMA_CHANNEL(chan)); + } +} + +bool imx233_dma_is_channel_error_irq(unsigned chan) +{ + if(APB_IS_APBX_CHANNEL(chan)) + return !!(HW_APBX_CTRL2 & + HW_APBX_CTRL2__CHx_ERROR_IRQ(APB_GET_DMA_CHANNEL(chan))); + else + return !!(HW_APBH_CTRL2 & + HW_APBH_CTRL2__CHx_ERROR_IRQ(APB_GET_DMA_CHANNEL(chan))); +} + +void imx233_dma_start_command(unsigned chan, struct apb_dma_command_t *cmd) +{ + if(APB_IS_APBX_CHANNEL(chan)) + { + HW_APBX_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd; + HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1; + } + else + { + HW_APBH_CHx_NXTCMDAR(APB_GET_DMA_CHANNEL(chan)) = (uint32_t)cmd; + HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)) = 1; + } +} + +void imx233_dma_wait_completion(unsigned chan) +{ + volatile uint32_t *sema; + if(APB_IS_APBX_CHANNEL(chan)) + sema = &HW_APBX_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); + else + sema = &HW_APBH_CHx_SEMA(APB_GET_DMA_CHANNEL(chan)); + + while(*sema & HW_APB_CHx_SEMA__PHORE_BM) + ; +} diff --git a/firmware/target/arm/imx233/dma-imx233.h b/firmware/target/arm/imx233/dma-imx233.h new file mode 100644 index 0000000000..ce13aba89f --- /dev/null +++ b/firmware/target/arm/imx233/dma-imx233.h @@ -0,0 +1,161 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by amaury Pouly + * + * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing + * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __DMA_IMX233_H__ +#define __DMA_IMX233_H__ + +#include "cpu.h" +#include "system.h" +#include "system-target.h" + +/******** + * APHB * + ********/ + +#define HW_APBH_BASE 0x80004000 + +/* APHB channels */ +#define HW_APBH_SSP(ssp) ssp + +#define HW_APBH_CTRL0 (*(volatile uint32_t *)(HW_APBH_BASE + 0x0)) +#define HW_APBH_CTRL0__FREEZE_CHANNEL(i) (1 << (i)) +#define HW_APBH_CTRL0__CLKGATE_CHANNEL(i) (1 << ((i) + 8)) +#define HW_APBH_CTRL0__RESET_CHANNEL(i) (1 << ((i) + 16)) +#define HW_APBH_CTRL0__APB_BURST4_EN (1 << 28) +#define HW_APBH_CTRL0__APB_BURST8_EN (1 << 29) + +#define HW_APBH_CTRL1 (*(volatile uint32_t *)(HW_APBH_BASE + 0x10)) +#define HW_APBH_CTRL1__CHx_CMDCMPLT_IRQ(i) (1 << (i)) +#define HW_APBH_CTRL1__CHx_CMDCMPLT_IRQ_EN(i) (1 << ((i) + 16)) + +#define HW_APBH_CTRL2 (*(volatile uint32_t *)(HW_APBH_BASE + 0x20)) +#define HW_APBH_CTRL2__CHx_ERROR_IRQ(i) (1 << (i)) +#define HW_APBH_CTRL2__CHx_ERROR_STATUS(i) (1 << ((i) + 16)) + +#define HW_APBH_CHx_CURCMDAR(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x40 + 0x70 * (i))) + +#define HW_APBH_CHx_NXTCMDAR(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x50 + 0x70 * (i))) + +#define HW_APBH_CHx_CMD(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x60 + 0x70 * (i))) + +#define HW_APBH_CHx_BAR(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x70 + 0x70 * (i))) + +#define HW_APBH_CHx_SEMA(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x80 + 0x70 * (i))) + +#define HW_APBH_CHx_DEBUG1(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0x90 + 0x70 * (i))) + +#define HW_APBH_CHx_DEBUG2(i) (*(volatile uint32_t *)(HW_APBH_BASE + 0xa0 + 0x70 * (i))) + +/******** + * APHX * + ********/ + +/* APHX channels */ +#define HW_APBX_AUDIO_ADC 0 +#define HW_APBX_AUDIO_DAC 1 + +#define HW_APBX_BASE 0x80024000 + +#define HW_APBX_CTRL0 (*(volatile uint32_t *)(HW_APBX_BASE + 0x0)) + +#define HW_APBX_CTRL1 (*(volatile uint32_t *)(HW_APBX_BASE + 0x10)) +#define HW_APBX_CTRL1__CHx_CMDCMPLT_IRQ(i) (1 << (i)) +#define HW_APBX_CTRL1__CHx_CMDCMPLT_IRQ_EN(i) (1 << ((i) + 16)) + +#define HW_APBX_CTRL2 (*(volatile uint32_t *)(HW_APBX_BASE + 0x20)) +#define HW_APBX_CTRL2__CHx_ERROR_IRQ(i) (1 << (i)) +#define HW_APBX_CTRL2__CHx_ERROR_STATUS(i) (1 << ((i) + 16)) + +#define HW_APBX_CHANNEL_CTRL (*(volatile uint32_t *)(HW_APBX_BASE + 0x30)) +#define HW_APBX_CHANNEL_CTRL__FREEZE_CHANNEL(i) (1 << (i)) +#define HW_APBX_CHANNEL_CTRL__RESET_CHANNEL(i) (1 << ((i) + 16)) + +#define HW_APBX_CHx_CURCMDAR(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x100 + (i) * 0x70)) + +#define HW_APBX_CHx_NXTCMDAR(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x110 + (i) * 0x70)) + +#define HW_APBX_CHx_CMD(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x120 + (i) * 0x70)) + +#define HW_APBX_CHx_BAR(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x130 + (i) * 0x70)) + +#define HW_APBX_CHx_SEMA(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x140 + (i) * 0x70)) + +#define HW_APBX_CHx_DEBUG1(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x150 + (i) * 0x70)) + +#define HW_APBX_CHx_DEBUG2(i) (*(volatile uint32_t *)(HW_APBX_BASE + 0x160 + (i) * 0x70)) + +/********** + * COMMON * + **********/ + +struct apb_dma_command_t +{ + struct apb_dma_command_t *next; + uint32_t cmd; + void *buffer; + /* PIO words follow */ +}; + +#define APBH_DMA_CHANNEL(i) i +#define APBX_DMA_CHANNEL(i) ((i) | 0x10) +#define APB_IS_APBX_CHANNEL(x) ((x) & 0x10) +#define APB_GET_DMA_CHANNEL(x) ((x) & 0xf) + +#define APB_SSP(ssp) APBH_DMA_CHANNEL(HW_APBH_SSP(ssp)) +#define APB_AUDIO_ADC APBX_DMA_CHANNEL(HW_APBX_AUDIO_ADC) + +#define HW_APB_CHx_CMD__COMMAND_BM 0x3 +#define HW_APB_CHx_CMD__COMMAND__NO_XFER 0 +#define HW_APB_CHx_CMD__COMMAND__WRITE 1 +#define HW_APB_CHx_CMD__COMMAND__READ 2 +#define HW_APB_CHx_CMD__COMMAND__SENSE 3 +#define HW_APB_CHx_CMD__CHAIN (1 << 2) +#define HW_APB_CHx_CMD__IRQONCMPLT (1 << 3) +/* those two are only available on APHB */ +#define HW_APBH_CHx_CMD__NANDLOCK (1 << 4) +#define HW_APBH_CHx_CMD__NANDWAIT4READY (1 << 5) +#define HW_APB_CHx_CMD__SEMAPHORE (1 << 6) +#define HW_APB_CHx_CMD__WAIT4ENDCMD (1 << 7) +#define HW_APB_CHx_CMD__HALTONTERMINATE (1 << 8) +#define HW_APB_CHx_CMD__CMDWORDS_BM 0xf000 +#define HW_APB_CHx_CMD__CMDWORDS_BP 12 +#define HW_APB_CHx_CMD__XFER_COUNT_BM 0xffff0000 +#define HW_APB_CHx_CMD__XFER_COUNT_BP 16 + +#define HW_APB_CHx_SEMA__PHORE_BM 0xff0000 +#define HW_APB_CHx_SEMA__PHORE_BP 16 + +void imx233_dma_init(void); +void imx233_dma_reset_channel(unsigned chan); +/* only apbh channel have clkgate control */ +void imx233_dma_clkgate_channel(unsigned chan, bool enable_clock); + +void imx233_dma_enable_channel_interrupt(unsigned chan, bool enable); +/* clear both channel complete and error bits */ +void imx233_dma_clear_channel_interrupt(unsigned chan); +bool imx233_dma_is_channel_error_irq(unsigned chan); +/* assume no command is in progress */ +void imx233_dma_start_command(unsigned chan, struct apb_dma_command_t *cmd); +void imx233_dma_wait_completion(unsigned chan); + +#endif // __DMA_IMX233_H__ diff --git a/firmware/target/arm/imx233/mmc-imx233.c b/firmware/target/arm/imx233/mmc-imx233.c new file mode 100644 index 0000000000..f56ff3725c --- /dev/null +++ b/firmware/target/arm/imx233/mmc-imx233.c @@ -0,0 +1,100 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "mmc.h" +#include "sdmmc.h" +#include "ssp-imx233.h" +#include "pinctrl-imx233.h" +#include "button-target.h" + +#ifdef SANSA_FUZEPLUS +#define MMC_SSP 2 +#else +#error You need to configure the ssp to use +#endif + +int mmc_init(void) +{ + imx233_ssp_start(MMC_SSP); + imx233_ssp_softreset(MMC_SSP); + imx233_ssp_set_mode(MMC_SSP, HW_SSP_CTRL1__SSP_MODE__SD_MMC); + #ifdef SANSA_FUZEPLUS + /** Sansa Fuze+ has an internal eMMC 8-bit wide flash, power gate is pin PWM3 */ + imx233_set_pin_function(1, 29, PINCTRL_FUNCTION_GPIO); + imx233_enable_gpio_output(1, 29, true); + imx233_set_gpio_output(1, 29, false); + + imx233_ssp_setup_ssp2_sd_mmc_pins(true, 8, PINCTRL_DRIVE_8mA); + #endif + /* SSPCLK @ 120MHz + * gives bitrate of 120 / 100 / 3 = 400kHz */ + imx233_ssp_set_timings(MMC_SSP, 100, 2); + imx233_ssp_set_timeout(MMC_SSP, 0xffff); + imx233_ssp_sd_mmc_power_up_sequence(MMC_SSP); + /* go to idle state */ + int ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, SD_GO_IDLE_STATE, 0, SSP_NO_RESP, NULL, 0, false, NULL); + if(ret != 0) + return -1; + /* send op cond until the card respond with busy bit set; it must complete within 1sec */ + unsigned timeout = current_tick + HZ; + do + { + uint32_t ocr; + ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 1, 0x40ff8000, SSP_SHORT_RESP, NULL, 0, false, &ocr); + if(ret == 0 && ocr & (1 << 31)) + break; + }while(!TIME_AFTER(current_tick, timeout)); + + if(ret != 0) + return -2; + + uint32_t cid[4]; + ret = imx233_ssp_sd_mmc_transfer(MMC_SSP, 2, 0, SSP_LONG_RESP, NULL, 0, false, cid); + if(ret != 0) + return -3; + + return 0; +} + +int mmc_num_drives(int first_drive) +{ + (void) first_drive; + return 1; +} + +int mmc_read_sectors(IF_MD2(int drive,) unsigned long start, int count, void* buf) +{ + IF_MD((void) drive); + (void) start; + (void) count; + (void) buf; + return -1; +} + +int mmc_write_sectors(IF_MD2(int drive,) unsigned long start, int count, const void* buf) +{ + IF_MD((void) drive); + (void) start; + (void) count; + (void) buf; + return -1; +} diff --git a/firmware/target/arm/imx233/pinctrl-imx233.h b/firmware/target/arm/imx233/pinctrl-imx233.h index 291b5c8ff7..4e3a9a035e 100644 --- a/firmware/target/arm/imx233/pinctrl-imx233.h +++ b/firmware/target/arm/imx233/pinctrl-imx233.h @@ -106,4 +106,20 @@ static inline void imx233_set_pin_function(unsigned bank, unsigned pin, unsigned __REG_SET(HW_PINCTRL_MUXSEL(2 * bank + pin / 16)) = function << (2 * (pin % 16)); } +static inline void imx233_enable_pin_pullup(unsigned bank, unsigned pin, bool enable) +{ + if(enable) + __REG_SET(HW_PINCTRL_PULL(bank)) = 1 << pin; + else + __REG_CLR(HW_PINCTRL_PULL(bank)) = 1 << pin; +} + +static inline void imx233_enable_pin_pullup_mask(unsigned bank, uint32_t pin_msk, bool enable) +{ + if(enable) + __REG_SET(HW_PINCTRL_PULL(bank)) = pin_msk; + else + __REG_CLR(HW_PINCTRL_PULL(bank)) = pin_msk; +} + #endif /* __PINCTRL_IMX233_H__ */ diff --git a/firmware/target/arm/imx233/sd-imx233.c b/firmware/target/arm/imx233/sd-imx233.c index eec1ce14db..6f30c7a3c6 100644 --- a/firmware/target/arm/imx233/sd-imx233.c +++ b/firmware/target/arm/imx233/sd-imx233.c @@ -18,7 +18,10 @@ * KIND, either express or implied. * ****************************************************************************/ +#include "config.h" +#include "system.h" #include "sd.h" +#include "sdmmc.h" int sd_init(void) { @@ -45,4 +48,15 @@ int sd_write_sectors(IF_MD2(int drive,) unsigned long start, int count, return -1; } +tCardInfo *card_get_info_target(int card_no) +{ + (void)card_no; + return NULL; +} + +int sd_num_drives(int first_drive) +{ + (void) first_drive; + return 0; +} diff --git a/firmware/target/arm/imx233/ssp-imx233.c b/firmware/target/arm/imx233/ssp-imx233.c new file mode 100644 index 0000000000..c6be869ce6 --- /dev/null +++ b/firmware/target/arm/imx233/ssp-imx233.c @@ -0,0 +1,307 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by amaury Pouly + * + * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing + * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "system.h" +#include "kernel.h" +#include "ssp-imx233.h" +#include "clkctrl-imx233.h" +#include "pinctrl-imx233.h" +#include "dma-imx233.h" + +/* Used for DMA */ +struct ssp_dma_command_t +{ + struct apb_dma_command_t dma; + /* PIO words */ + uint32_t ctrl0; + uint32_t cmd0; + uint32_t cmd1; +}; + +static int ssp_in_use = 0; +static struct mutex ssp_mutex[2]; +static struct semaphore ssp_sema[2]; +static struct ssp_dma_command_t ssp_dma_cmd[2]; + +void INT_SSP(int ssp) +{ + /* reset dma channel on error */ + if(imx233_dma_is_channel_error_irq(APB_SSP(ssp))) + imx233_dma_reset_channel(APB_SSP(ssp)); + /* clear irq flags */ + imx233_dma_clear_channel_interrupt(APB_SSP(ssp)); + semaphore_release(&ssp_sema[ssp - 1]); +} + +void INT_SSP1_DMA(void) +{ + INT_SSP(1); +} + +void INT_SSP2_DMA(void) +{ + INT_SSP(2); +} + +void INT_SSP1_ERROR(void) +{ + panicf("ssp1 error"); +} + +void INT_SSP2_ERROR(void) +{ + panicf("ssp2 error"); +} + +void imx233_ssp_init(void) +{ + /* power down */ + __REG_SET(HW_SSP_CTRL0(1)) = __BLOCK_CLKGATE; + __REG_SET(HW_SSP_CTRL0(2)) = __BLOCK_CLKGATE; + + ssp_in_use = 0; + semaphore_init(&ssp_sema[0], 1, 0); + semaphore_init(&ssp_sema[1], 1, 0); + mutex_init(&ssp_mutex[0]); + mutex_init(&ssp_mutex[1]); +} + +void imx233_ssp_start(int ssp) +{ + /* Gate block */ + __REG_CLR(HW_SSP_CTRL0(ssp)) = __BLOCK_CLKGATE; + while(HW_SSP_CTRL0(ssp) & __BLOCK_CLKGATE); + /* Gate dma channel */ + imx233_dma_clkgate_channel(APB_SSP(ssp), true); + /* If first block to start, start SSP clock */ + if(ssp_in_use == 0) + { + /* fracdiv = 18 => clk_io = pll = 480Mhz + * intdiv = 4 => clk_ssp = 120Mhz */ + imx233_set_fractional_divisor(CLK_IO, 18); + imx233_enable_clock(CLK_SSP, false); + imx233_set_clock_divisor(CLK_SSP, 4); + imx233_set_bypass_pll(CLK_SSP, false); /* use IO */ + imx233_enable_clock(CLK_SSP, true); + } + ssp_in_use++; +} + +void imx233_ssp_stop(int ssp) +{ + /* Gate off */ + __REG_SET(HW_SSP_CTRL0(ssp)) = __BLOCK_CLKGATE; + /* Gate off dma */ + imx233_dma_clkgate_channel(APB_SSP(ssp), false); + /* If last block to stop, stop SSP clock */ + ssp_in_use--; + if(ssp_in_use == 0) + { + imx233_enable_clock(CLK_SSP, false); + imx233_set_fractional_divisor(CLK_IO, 0); + } +} + +void imx233_ssp_softreset(int ssp) +{ + imx233_reset_block(&HW_SSP_CTRL0(ssp)); +} + +void imx233_ssp_set_timings(int ssp, int divide, int rate) +{ + __REG_CLR(HW_SSP_TIMING(ssp)) = + HW_SSP_TIMING__CLOCK_DIVIDE_BM | HW_SSP_TIMING__CLOCK_RATE_BM; + __REG_SET(HW_SSP_TIMING(ssp)) = + divide << HW_SSP_TIMING__CLOCK_DIVIDE_BP | rate; +} + +void imx233_ssp_set_timeout(int ssp, int timeout) +{ + __REG_CLR(HW_SSP_TIMING(ssp)) = HW_SSP_TIMING__CLOCK_TIMEOUT_BM; + __REG_SET(HW_SSP_TIMING(ssp)) = + timeout << HW_SSP_TIMING__CLOCK_TIMEOUT_BP; +} + +#if 0 +static void setup_ssp_sd_pins(int ssp) +{ + imx233_set_pin_function(1, 29, PINCTRL_FUNCTION_GPIO); + imx233_enable_gpio_output(1, 29, true); + imx233_set_gpio_output(1, 29, false); + + if(ssp == 1) + { + /* SSP_SCK: drive 8mA */ + imx233_set_pin_drive_strength(2, 6, PINCTRL_DRIVE_8mA); + /* SSP_{SCK,DATA{3,2,1,0},DETECT,CMD} */ + imx233_set_pin_function(2, 6, PINCTRL_FUNCTION_MAIN); + imx233_set_pin_function(2, 5, PINCTRL_FUNCTION_MAIN); + imx233_set_pin_function(2, 4, PINCTRL_FUNCTION_MAIN); + imx233_set_pin_function(2, 3, PINCTRL_FUNCTION_MAIN); + imx233_set_pin_function(2, 2, PINCTRL_FUNCTION_MAIN); + imx233_set_pin_function(2, 1, PINCTRL_FUNCTION_MAIN); + imx233_set_pin_function(2, 0, PINCTRL_FUNCTION_MAIN); + /* SSP_CMD: pullup */ + imx233_enable_pin_pullup(2, 0, true); + imx233_enable_pin_pullup(2, 2, true); + imx233_enable_pin_pullup(2, 3, true); + imx233_enable_pin_pullup(2, 4, true); + imx233_enable_pin_pullup(2, 5, true); + } + else + { + + } +} +#endif + +void imx233_ssp_setup_ssp2_sd_mmc_pins(bool enable_pullups, unsigned bus_width, + unsigned drive_strength) +{ + /* SSP_{CMD,SCK} */ + imx233_set_pin_drive_strength(0, 20, drive_strength); + imx233_set_pin_drive_strength(0, 24, drive_strength); + imx233_set_pin_function(0, 20, PINCTRL_FUNCTION_ALT2); + imx233_set_pin_function(0, 24, PINCTRL_FUNCTION_ALT2); + imx233_enable_pin_pullup(0, 20, enable_pullups); + /* SSP_DATA{0-7}*/ + imx233_set_pin_drive_strength(0, 0, drive_strength); + imx233_set_pin_function(0, 0, PINCTRL_FUNCTION_ALT2); + imx233_enable_pin_pullup(0, 0, enable_pullups); + + if(bus_width >= 4) + { + imx233_set_pin_drive_strength(0, 1, drive_strength); + imx233_set_pin_drive_strength(0, 2, drive_strength); + imx233_set_pin_drive_strength(0, 3, drive_strength); + imx233_set_pin_function(0, 1, PINCTRL_FUNCTION_ALT2); + imx233_set_pin_function(0, 2, PINCTRL_FUNCTION_ALT2); + imx233_set_pin_function(0, 3, PINCTRL_FUNCTION_ALT2); + imx233_enable_pin_pullup(0, 1, enable_pullups); + imx233_enable_pin_pullup(0, 2, enable_pullups); + imx233_enable_pin_pullup(0, 3, enable_pullups); + } + if(bus_width >= 8) + { + imx233_set_pin_drive_strength(0, 4, drive_strength); + imx233_set_pin_drive_strength(0, 5, drive_strength); + imx233_set_pin_drive_strength(0, 6, drive_strength); + imx233_set_pin_drive_strength(0, 7, drive_strength); + imx233_set_pin_function(0, 4, PINCTRL_FUNCTION_ALT2); + imx233_set_pin_function(0, 5, PINCTRL_FUNCTION_ALT2); + imx233_set_pin_function(0, 6, PINCTRL_FUNCTION_ALT2); + imx233_set_pin_function(0, 7, PINCTRL_FUNCTION_ALT2); + imx233_enable_pin_pullup(0, 4, enable_pullups); + imx233_enable_pin_pullup(0, 5, enable_pullups); + imx233_enable_pin_pullup(0, 6, enable_pullups); + imx233_enable_pin_pullup(0, 7, enable_pullups); + } + + imx233_enable_gpio_output_mask(0, 0x11000ff, false); + imx233_set_gpio_output_mask(0, 0x11000ff, false); +} + +void imx233_ssp_set_mode(int ssp, unsigned mode) +{ + switch(mode) + { + case HW_SSP_CTRL1__SSP_MODE__SD_MMC: + /* clear mode and word length */ + __REG_CLR(HW_SSP_CTRL1(ssp)) = + HW_SSP_CTRL1__SSP_MODE_BM | HW_SSP_CTRL1__WORD_LENGTH_BM; + /* set mode, set word length to 8-bit, polarity and enable dma */ + __REG_SET(HW_SSP_CTRL1(ssp)) = mode | + HW_SSP_CTRL1__WORD_LENGTH__EIGHT_BITS << HW_SSP_CTRL1__WORD_LENGTH_BP | + HW_SSP_CTRL1__POLARITY | HW_SSP_CTRL1__DMA_ENABLE; + break; + default: return; + } +} + +enum imx233_ssp_error_t imx233_ssp_sd_mmc_transfer(int ssp, uint8_t cmd, uint32_t cmd_arg, + enum imx233_ssp_resp_t resp, void *buffer, int xfer_size, bool read, uint32_t *resp_ptr) +{ + mutex_lock(&ssp_mutex[ssp - 1]); + /* Enable all interrupts */ + imx233_enable_interrupt(INT_SRC_SSP_DMA(ssp), true); + imx233_dma_enable_channel_interrupt(APB_SSP(ssp), true); + /* Assume only one block so ignore block_count and block_size */ + ssp_dma_cmd[ssp - 1].cmd0 = cmd | HW_SSP_CMD0__APPEND_8CYC; + ssp_dma_cmd[ssp - 1].cmd1 = cmd_arg; + /* setup all flags and run */ + ssp_dma_cmd[ssp - 1].ctrl0 = xfer_size | HW_SSP_CTRL0__ENABLE | + HW_SSP_CTRL0__IGNORE_CRC | + (resp != SSP_NO_RESP ? HW_SSP_CTRL0__GET_RESP | HW_SSP_CTRL0__WAIT_FOR_IRQ : 0) | + (resp == SSP_LONG_RESP ? HW_SSP_CTRL0__LONG_RESP : 0) | + HW_SSP_CTRL0__BUS_WIDTH__ONE_BIT << HW_SSP_CTRL0__BUS_WIDTH_BP | + (buffer ? HW_SSP_CTRL0__DATA_XFER : 0) | + (read ? HW_SSP_CTRL0__READ : 0); + /* setup the dma parameters */ + ssp_dma_cmd[ssp - 1].dma.buffer = buffer; + ssp_dma_cmd[ssp - 1].dma.next = NULL; + ssp_dma_cmd[ssp - 1].dma.cmd = + (buffer == NULL ? HW_APB_CHx_CMD__COMMAND__NO_XFER : + read ? HW_APB_CHx_CMD__COMMAND__WRITE : HW_APB_CHx_CMD__COMMAND__READ) | + HW_APB_CHx_CMD__IRQONCMPLT | HW_APB_CHx_CMD__SEMAPHORE | + HW_APB_CHx_CMD__WAIT4ENDCMD | HW_APB_CHx_CMD__HALTONTERMINATE | + (3 << HW_APB_CHx_CMD__CMDWORDS_BP) | + (xfer_size << HW_APB_CHx_CMD__XFER_COUNT_BP); + + imx233_dma_start_command(APB_SSP(ssp), &ssp_dma_cmd[ssp - 1].dma); + + /* the SSP hardware already has a timeout but we never know; 1 sec is a maximum + * for all operations */ + enum imx233_ssp_error_t ret; + + if(semaphore_wait(&ssp_sema[ssp - 1], HZ) == OBJ_WAIT_TIMEDOUT) + ret = SSP_TIMEOUT; + else if((HW_SSP_CTRL1(ssp) & HW_SSP_CTRL1__ALL_IRQ) == 0) + ret = SSP_SUCCESS; + else if(HW_SSP_CTRL1(ssp) & (HW_SSP_CTRL1__RESP_TIMEOUT_IRQ | + HW_SSP_CTRL1__DATA_TIMEOUT_IRQ | HW_SSP_CTRL1__RECV_TIMEOUT_IRQ)) + ret = SSP_TIMEOUT; + else + ret = SSP_ERROR; + + if(ret == SSP_SUCCESS && resp_ptr != NULL) + { + if(resp != SSP_NO_RESP) + *resp_ptr++ = HW_SSP_SDRESP0(ssp); + if(resp == SSP_LONG_RESP) + { + *resp_ptr++ = HW_SSP_SDRESP1(ssp); + *resp_ptr++ = HW_SSP_SDRESP2(ssp); + *resp_ptr++ = HW_SSP_SDRESP3(ssp); + } + } + mutex_unlock(&ssp_mutex[ssp - 1]); + return ret; +} + +void imx233_ssp_sd_mmc_power_up_sequence(int ssp) +{ + __REG_CLR(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__SLOW_CLKING_EN; + __REG_SET(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__CONT_CLKING_EN; + mdelay(1); + __REG_CLR(HW_SSP_CMD0(ssp)) = HW_SSP_CMD0__CONT_CLKING_EN; +} diff --git a/firmware/target/arm/imx233/ssp-imx233.h b/firmware/target/arm/imx233/ssp-imx233.h new file mode 100644 index 0000000000..e9bdf62b27 --- /dev/null +++ b/firmware/target/arm/imx233/ssp-imx233.h @@ -0,0 +1,162 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by amaury Pouly + * + * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing + * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __SSP_IMX233_H__ +#define __SSP_IMX233_H__ + +#include "cpu.h" +#include "system.h" +#include "system-target.h" + +/* ssp can value 1 or 2 */ +#define __SSP_SELECT(ssp, ssp1, ssp2) ((ssp) == 1 ? (ssp1) : (ssp2)) + +#define INT_SRC_SSP_DMA(ssp) __SSP_SELECT(ssp, INT_SRC_SSP1_DMA, INT_SRC_SSP2_DMA) +#define INT_SRC_SSP_ERROR(ssp) __SSP_SELECT(ssp, INT_SRC_SSP1_ERROR, INT_SRC_SSP2_ERROR) + +#define HW_SSP1_BASE 0x80010000 +#define HW_SSP2_BASE 0x80034000 + +#define HW_SSP_BASE(ssp) __SSP_SELECT(ssp, HW_SSP1_BASE, HW_SSP2_BASE) + +#define HW_SSP_CTRL0(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x0)) +#define HW_SSP_CTRL0__RUN (1 << 29) +#define HW_SSP_CTRL0__SDIO_IRQ_CHECK (1 << 28) +#define HW_SSP_CTRL0__LOCK_CS (1 << 27) +#define HW_SSP_CTRL0__IGNORE_CRC (1 << 26) +#define HW_SSP_CTRL0__READ (1 << 25) +#define HW_SSP_CTRL0__DATA_XFER (1 << 24) +#define HW_SSP_CTRL0__BUS_WIDTH_BM (3 << 22) +#define HW_SSP_CTRL0__BUS_WIDTH_BP 22 +#define HW_SSP_CTRL0__BUS_WIDTH__ONE_BIT 0 +#define HW_SSP_CTRL0__BUS_WIDTH__FOUR_BIT 1 +#define HW_SSP_CTRL0__BUS_WIDTH__EIGHT_BIT 2 +#define HW_SSP_CTRL0__WAIT_FOR_IRQ (1 << 21) +#define HW_SSP_CTRL0__WAIT_FOR_CMD (1 << 20) +#define HW_SSP_CTRL0__LONG_RESP (1 << 19) +#define HW_SSP_CTRL0__CHECK_RESP (1 << 18) +#define HW_SSP_CTRL0__GET_RESP (1 << 17) +#define HW_SSP_CTRL0__ENABLE (1 << 16) +#define HW_SSP_CTRL0__XFER_COUNT_BM 0xffff + + +#define HW_SSP_CMD0(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x10)) +#define HW_SSP_CMD0__SLOW_CLKING_EN (1 << 22) +#define HW_SSP_CMD0__CONT_CLKING_EN (1 << 21) +#define HW_SSP_CMD0__APPEND_8CYC (1 << 20) +#define HW_SSP_CMD0__BLOCK_SIZE_BM (0xf << 16) +#define HW_SSP_CMD0__BLOCK_SIZE_BP 16 +#define HW_SSP_CMD0__BLOCK_COUNT_BM (0xff << 8) +#define HW_SSP_CMD0__BLOCK_COUNT_BP 16 +#define HW_SSP_CMD0__CMD_BM 0xff + +#define HW_SSP_CMD1(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x20)) + +#define HW_SSP_TIMING(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x50)) +#define HW_SSP_TIMING__CLOCK_TIMEOUT_BM 0xffff0000 +#define HW_SSP_TIMING__CLOCK_TIMEOUT_BP 16 +#define HW_SSP_TIMING__CLOCK_DIVIDE_BM 0xff00 +#define HW_SSP_TIMING__CLOCK_DIVIDE_BP 8 +#define HW_SSP_TIMING__CLOCK_RATE_BM 0xff + +#define HW_SSP_CTRL1(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x60)) +#define HW_SSP_CTRL1__SDIO_IRQ (1 << 31) +#define HW_SSP_CTRL1__SDIO_IRQ_EN (1 << 30) +#define HW_SSP_CTRL1__RESP_ERR_IRQ (1 << 29) +#define HW_SSP_CTRL1__RESP_ERR_IRQ_EN (1 << 28) +#define HW_SSP_CTRL1__RESP_TIMEOUT_IRQ (1 << 27) +#define HW_SSP_CTRL1__RESP_TIMEOUT_IRQ_EN (1 << 26) +#define HW_SSP_CTRL1__DATA_TIMEOUT_IRQ (1 << 25) +#define HW_SSP_CTRL1__DATA_TIMEOUT_IRQ_EN (1 << 24) +#define HW_SSP_CTRL1__DATA_CRC_IRQ (1 << 23) +#define HW_SSP_CTRL1__DATA_CRC_IRQ_EN (1 << 22) +#define HW_SSP_CTRL1__FIFO_UNDERRUN_IRQ (1 << 21) +#define HW_SSP_CTRL1__FIFO_UNDERRUN_IRQ_EN (1 << 20) +#define HW_SSP_CTRL1__RECV_TIMEOUT_IRQ (1 << 17) +#define HW_SSP_CTRL1__RECV_TIMEOUT_IRQ_EN (1 << 16) +#define HW_SSP_CTRL1__FIFO_OVERRUN_IRQ (1 << 15) +#define HW_SSP_CTRL1__FIFO_OVERRUN_IRQ_EN (1 << 14) +#define HW_SSP_CTRL1__DMA_ENABLE (1 << 13) +#define HW_SSP_CTRL1__SLAVE_OUT_DISABLE (1 << 11) +#define HW_SSP_CTRL1__PHASE (1 << 10) +#define HW_SSP_CTRL1__POLARITY (1 << 9) +#define HW_SSP_CTRL1__SLAVE_MODE (1 << 8) +#define HW_SSP_CTRL1__WORD_LENGTH_BM (0xf << 4) +#define HW_SSP_CTRL1__WORD_LENGTH_BP 4 +#define HW_SSP_CTRL1__WORD_LENGTH__EIGHT_BITS 0x7 +#define HW_SSP_CTRL1__SSP_MODE_BM 0xf +#define HW_SSP_CTRL1__SSP_MODE__SD_MMC 0x3 +#define HW_SSP_CTRL1__ALL_IRQ 0xaaa28000 + +#define HW_SSP_DATA(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x70)) + +#define HW_SSP_SDRESP0(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x80)) +#define HW_SSP_SDRESP1(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x90)) +#define HW_SSP_SDRESP2(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0xA0)) +#define HW_SSP_SDRESP3(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0xB0)) + +#define HW_SSP_STATUS(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0xC0)) +#define HW_SSP_STATUS__RECV_TIMEOUT_STAT (1 << 11) +#define HW_SSP_STATUS__TIMEOUT (1 << 12) +#define HW_SSP_STATUS__DATA_CRC_ERR (1 << 13) +#define HW_SSP_STATUS__RESP_TIMEOUT (1 << 14) +#define HW_SSP_STATUS__RESP_ERR (1 << 15) +#define HW_SSP_STATUS__RESP_CRC_ERR (1 << 16) +#define HW_SSP_STATUS__ALL_ERRORS 0x1f800 + +#define HW_SSP_DEBUG(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x100)) + +#define HW_SSP_VERSION(ssp) (*(volatile uint32_t *)(HW_SSP_BASE(ssp) + 0x110)) + +enum imx233_ssp_error_t +{ + SSP_SUCCESS = 0, + SSP_ERROR = -1, + SSP_TIMEOUT = -2, +}; + +enum imx233_ssp_resp_t +{ + SSP_NO_RESP = 0, + SSP_SHORT_RESP, + SSP_LONG_RESP +}; + +void imx233_ssp_init(void); +void imx233_ssp_start(int ssp); +void imx233_ssp_stop(int ssp); +/* only softreset between start and stop or it might hang ! */ +void imx233_ssp_softreset(int ssp); +void imx233_ssp_set_timings(int ssp, int divide, int rate); +void imx233_ssp_set_timeout(int ssp, int timeout); +void imx233_ssp_set_mode(int ssp, unsigned mode); +/* SD/MMC facilities */ +enum imx233_ssp_error_t imx233_ssp_sd_mmc_transfer(int ssp, uint8_t cmd, uint32_t cmd_arg, + enum imx233_ssp_resp_t resp, void *buffer, int xfer_size, bool read, uint32_t *resp_ptr); +void imx233_ssp_setup_ssp2_sd_mmc_pins(bool enable_pullups, unsigned bus_width, + unsigned drive_strength); +/* SD/MMC requires that the card be provided the clock during an init sequence of + * at least 1msec (or 74 clocks). Does NOT touch the clock so it has to be correct. */ +void imx233_ssp_sd_mmc_power_up_sequence(int ssp); + +#endif /* __SSP_IMX233_H__ */ diff --git a/firmware/target/arm/imx233/system-imx233.c b/firmware/target/arm/imx233/system-imx233.c index aedffd1cf6..9c843c48c1 100644 --- a/firmware/target/arm/imx233/system-imx233.c +++ b/firmware/target/arm/imx233/system-imx233.c @@ -27,6 +27,8 @@ #include "clkctrl-imx233.h" #include "pinctrl-imx233.h" #include "timrot-imx233.h" +#include "dma-imx233.h" +#include "ssp-imx233.h" #include "lcd.h" #include "backlight-target.h" @@ -44,6 +46,10 @@ default_interrupt(INT_TIMER2); default_interrupt(INT_TIMER3); default_interrupt(INT_LCDIF_DMA); default_interrupt(INT_LCDIF_ERROR); +default_interrupt(INT_SSP1_DMA); +default_interrupt(INT_SSP1_ERROR); +default_interrupt(INT_SSP2_DMA); +default_interrupt(INT_SSP2_ERROR); typedef void (*isr_t)(void); @@ -56,6 +62,10 @@ static isr_t isr_table[INT_SRC_NR_SOURCES] = [INT_SRC_TIMER(3)] = INT_TIMER3, [INT_SRC_LCDIF_DMA] = INT_LCDIF_DMA, [INT_SRC_LCDIF_ERROR] = INT_LCDIF_ERROR, + [INT_SRC_SSP1_DMA] = INT_SSP1_DMA, + [INT_SRC_SSP1_ERROR] = INT_SSP1_ERROR, + [INT_SRC_SSP2_DMA] = INT_SSP2_DMA, + [INT_SRC_SSP2_ERROR] = INT_SSP2_ERROR }; static void UIRQ(void) @@ -128,6 +138,8 @@ void system_init(void) imx233_pinctrl_init(); imx233_timrot_init(); + imx233_dma_init(); + imx233_ssp_init(); } void power_off(void) diff --git a/firmware/target/arm/imx233/system-target.h b/firmware/target/arm/imx233/system-target.h index 4d767b3a9f..163eacb41f 100644 --- a/firmware/target/arm/imx233/system-target.h +++ b/firmware/target/arm/imx233/system-target.h @@ -57,7 +57,11 @@ #define HW_ICOLL_INTERRUPT__SOFTIRQ 0x8 #define HW_ICOLL_INTERRUPT__ENFIQ 0x10 +#define INT_SRC_SSP2_ERROR 2 #define INT_SRC_USB_CTRL 11 +#define INT_SRC_SSP1_DMA 14 +#define INT_SRC_SSP1_ERROR 15 +#define INT_SRC_SSP2_DMA 20 #define INT_SRC_TIMER(nr) (28 + (nr)) #define INT_SRC_LCDIF_DMA 45 #define INT_SRC_LCDIF_ERROR 46 diff --git a/firmware/target/arm/imx233/usb-imx233.c b/firmware/target/arm/imx233/usb-imx233.c new file mode 100644 index 0000000000..83e50839b4 --- /dev/null +++ b/firmware/target/arm/imx233/usb-imx233.c @@ -0,0 +1,76 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2011 by Amaury Pouly + * + * 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 software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "config.h" +#include "cpu.h" +#include "string.h" +#include "usb.h" +#include "usb_drv.h" +#include "usb_core.h" +#include "usb-target.h" +#include "system.h" +#include "system-target.h" + +int usb_status = USB_EXTRACTED; + +void usb_drv_usb_detect_event() +{ + usb_status_event(USB_INSERTED); +} + +void usb_attach(void) +{ + usb_drv_attach(); +} + +void usb_drv_int_enable(bool enable) +{ + imx233_enable_interrupt(INT_SRC_USB_CTRL, enable); +} + +void INT_USB_CTRL(void) +{ + printf("usb int"); + usb_drv_int(); +} + +void usb_init_device(void) +{ + usb_drv_startup(); +} + +int usb_detect(void) +{ + return usb_status; +} + +bool usb_plugged(void) +{ + return true; +} + +void usb_enable(bool on) +{ + if(on) + usb_core_init(); + else + usb_core_exit(); +} -- cgit v1.2.3