📄 pata_bf54x.c
字号:
/* * File: drivers/ata/pata_bf54x.c * Author: Sonic Zhang <sonic.zhang@analog.com> * * Created: * Description: PATA Driver for blackfin 54x * * Modified: * Copyright 2007 Analog Devices Inc. * * Bugs: Enter bugs at http://blackfin.uclinux.org/ * * 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, see the file COPYING, or write * to the Free Software Foundation, Inc., * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */#include <linux/kernel.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/delay.h>#include <linux/device.h>#include <scsi/scsi_host.h>#include <linux/libata.h>#include <linux/platform_device.h>#include <asm/dma.h>#include <asm/gpio.h>#include <asm/portmux.h>#define DRV_NAME "pata-bf54x"#define DRV_VERSION "0.9"#define ATA_REG_CTRL 0x0E#define ATA_REG_ALTSTATUS ATA_REG_CTRL/* These are the offset of the controller's registers */#define ATAPI_OFFSET_CONTROL 0x00#define ATAPI_OFFSET_STATUS 0x04#define ATAPI_OFFSET_DEV_ADDR 0x08#define ATAPI_OFFSET_DEV_TXBUF 0x0c#define ATAPI_OFFSET_DEV_RXBUF 0x10#define ATAPI_OFFSET_INT_MASK 0x14#define ATAPI_OFFSET_INT_STATUS 0x18#define ATAPI_OFFSET_XFER_LEN 0x1c#define ATAPI_OFFSET_LINE_STATUS 0x20#define ATAPI_OFFSET_SM_STATE 0x24#define ATAPI_OFFSET_TERMINATE 0x28#define ATAPI_OFFSET_PIO_TFRCNT 0x2c#define ATAPI_OFFSET_DMA_TFRCNT 0x30#define ATAPI_OFFSET_UMAIN_TFRCNT 0x34#define ATAPI_OFFSET_UDMAOUT_TFRCNT 0x38#define ATAPI_OFFSET_REG_TIM_0 0x40#define ATAPI_OFFSET_PIO_TIM_0 0x44#define ATAPI_OFFSET_PIO_TIM_1 0x48#define ATAPI_OFFSET_MULTI_TIM_0 0x50#define ATAPI_OFFSET_MULTI_TIM_1 0x54#define ATAPI_OFFSET_MULTI_TIM_2 0x58#define ATAPI_OFFSET_ULTRA_TIM_0 0x60#define ATAPI_OFFSET_ULTRA_TIM_1 0x64#define ATAPI_OFFSET_ULTRA_TIM_2 0x68#define ATAPI_OFFSET_ULTRA_TIM_3 0x6c#define ATAPI_GET_CONTROL(base)\ bfin_read16(base + ATAPI_OFFSET_CONTROL)#define ATAPI_SET_CONTROL(base, val)\ bfin_write16(base + ATAPI_OFFSET_CONTROL, val)#define ATAPI_GET_STATUS(base)\ bfin_read16(base + ATAPI_OFFSET_STATUS)#define ATAPI_GET_DEV_ADDR(base)\ bfin_read16(base + ATAPI_OFFSET_DEV_ADDR)#define ATAPI_SET_DEV_ADDR(base, val)\ bfin_write16(base + ATAPI_OFFSET_DEV_ADDR, val)#define ATAPI_GET_DEV_TXBUF(base)\ bfin_read16(base + ATAPI_OFFSET_DEV_TXBUF)#define ATAPI_SET_DEV_TXBUF(base, val)\ bfin_write16(base + ATAPI_OFFSET_DEV_TXBUF, val)#define ATAPI_GET_DEV_RXBUF(base)\ bfin_read16(base + ATAPI_OFFSET_DEV_RXBUF)#define ATAPI_SET_DEV_RXBUF(base, val)\ bfin_write16(base + ATAPI_OFFSET_DEV_RXBUF, val)#define ATAPI_GET_INT_MASK(base)\ bfin_read16(base + ATAPI_OFFSET_INT_MASK)#define ATAPI_SET_INT_MASK(base, val)\ bfin_write16(base + ATAPI_OFFSET_INT_MASK, val)#define ATAPI_GET_INT_STATUS(base)\ bfin_read16(base + ATAPI_OFFSET_INT_STATUS)#define ATAPI_SET_INT_STATUS(base, val)\ bfin_write16(base + ATAPI_OFFSET_INT_STATUS, val)#define ATAPI_GET_XFER_LEN(base)\ bfin_read16(base + ATAPI_OFFSET_XFER_LEN)#define ATAPI_SET_XFER_LEN(base, val)\ bfin_write16(base + ATAPI_OFFSET_XFER_LEN, val)#define ATAPI_GET_LINE_STATUS(base)\ bfin_read16(base + ATAPI_OFFSET_LINE_STATUS)#define ATAPI_GET_SM_STATE(base)\ bfin_read16(base + ATAPI_OFFSET_SM_STATE)#define ATAPI_GET_TERMINATE(base)\ bfin_read16(base + ATAPI_OFFSET_TERMINATE)#define ATAPI_SET_TERMINATE(base, val)\ bfin_write16(base + ATAPI_OFFSET_TERMINATE, val)#define ATAPI_GET_PIO_TFRCNT(base)\ bfin_read16(base + ATAPI_OFFSET_PIO_TFRCNT)#define ATAPI_GET_DMA_TFRCNT(base)\ bfin_read16(base + ATAPI_OFFSET_DMA_TFRCNT)#define ATAPI_GET_UMAIN_TFRCNT(base)\ bfin_read16(base + ATAPI_OFFSET_UMAIN_TFRCNT)#define ATAPI_GET_UDMAOUT_TFRCNT(base)\ bfin_read16(base + ATAPI_OFFSET_UDMAOUT_TFRCNT)#define ATAPI_GET_REG_TIM_0(base)\ bfin_read16(base + ATAPI_OFFSET_REG_TIM_0)#define ATAPI_SET_REG_TIM_0(base, val)\ bfin_write16(base + ATAPI_OFFSET_REG_TIM_0, val)#define ATAPI_GET_PIO_TIM_0(base)\ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_0)#define ATAPI_SET_PIO_TIM_0(base, val)\ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_0, val)#define ATAPI_GET_PIO_TIM_1(base)\ bfin_read16(base + ATAPI_OFFSET_PIO_TIM_1)#define ATAPI_SET_PIO_TIM_1(base, val)\ bfin_write16(base + ATAPI_OFFSET_PIO_TIM_1, val)#define ATAPI_GET_MULTI_TIM_0(base)\ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_0)#define ATAPI_SET_MULTI_TIM_0(base, val)\ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_0, val)#define ATAPI_GET_MULTI_TIM_1(base)\ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_1)#define ATAPI_SET_MULTI_TIM_1(base, val)\ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_1, val)#define ATAPI_GET_MULTI_TIM_2(base)\ bfin_read16(base + ATAPI_OFFSET_MULTI_TIM_2)#define ATAPI_SET_MULTI_TIM_2(base, val)\ bfin_write16(base + ATAPI_OFFSET_MULTI_TIM_2, val)#define ATAPI_GET_ULTRA_TIM_0(base)\ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_0)#define ATAPI_SET_ULTRA_TIM_0(base, val)\ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_0, val)#define ATAPI_GET_ULTRA_TIM_1(base)\ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_1)#define ATAPI_SET_ULTRA_TIM_1(base, val)\ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_1, val)#define ATAPI_GET_ULTRA_TIM_2(base)\ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_2)#define ATAPI_SET_ULTRA_TIM_2(base, val)\ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_2, val)#define ATAPI_GET_ULTRA_TIM_3(base)\ bfin_read16(base + ATAPI_OFFSET_ULTRA_TIM_3)#define ATAPI_SET_ULTRA_TIM_3(base, val)\ bfin_write16(base + ATAPI_OFFSET_ULTRA_TIM_3, val)/** * PIO Mode - Frequency compatibility *//* mode: 0 1 2 3 4 */static const u32 pio_fsclk[] ={ 33333333, 33333333, 33333333, 33333333, 33333333 };/** * MDMA Mode - Frequency compatibility *//* mode: 0 1 2 */static const u32 mdma_fsclk[] = { 33333333, 33333333, 33333333 };/** * UDMA Mode - Frequency compatibility * * UDMA5 - 100 MB/s - SCLK = 133 MHz * UDMA4 - 66 MB/s - SCLK >= 80 MHz * UDMA3 - 44.4 MB/s - SCLK >= 50 MHz * UDMA2 - 33 MB/s - SCLK >= 40 MHz *//* mode: 0 1 2 3 4 5 */static const u32 udma_fsclk[] ={ 33333333, 33333333, 40000000, 50000000, 80000000, 133333333 };/** * Register transfer timing table *//* mode: 0 1 2 3 4 *//* Cycle Time */static const u32 reg_t0min[] = { 600, 383, 330, 180, 120 };/* DIOR/DIOW to end cycle */static const u32 reg_t2min[] = { 290, 290, 290, 70, 25 };/* DIOR/DIOW asserted pulse width */static const u32 reg_teocmin[] = { 290, 290, 290, 80, 70 };/** * PIO timing table *//* mode: 0 1 2 3 4 *//* Cycle Time */static const u32 pio_t0min[] = { 600, 383, 240, 180, 120 };/* Address valid to DIOR/DIORW */static const u32 pio_t1min[] = { 70, 50, 30, 30, 25 };/* DIOR/DIOW to end cycle */static const u32 pio_t2min[] = { 165, 125, 100, 80, 70 };/* DIOR/DIOW asserted pulse width */static const u32 pio_teocmin[] = { 165, 125, 100, 70, 25 };/* DIOW data hold */static const u32 pio_t4min[] = { 30, 20, 15, 10, 10 };/* ****************************************************************** * Multiword DMA timing table * ****************************************************************** *//* mode: 0 1 2 *//* Cycle Time */static const u32 mdma_t0min[] = { 480, 150, 120 };/* DIOR/DIOW asserted pulse width */static const u32 mdma_tdmin[] = { 215, 80, 70 };/* DMACK to read data released */static const u32 mdma_thmin[] = { 20, 15, 10 };/* DIOR/DIOW to DMACK hold */static const u32 mdma_tjmin[] = { 20, 5, 5 };/* DIOR negated pulse width */static const u32 mdma_tkrmin[] = { 50, 50, 25 };/* DIOR negated pulse width */static const u32 mdma_tkwmin[] = { 215, 50, 25 };/* CS[1:0] valid to DIOR/DIOW */static const u32 mdma_tmmin[] = { 50, 30, 25 };/* DMACK to read data released */static const u32 mdma_tzmax[] = { 20, 25, 25 };/** * Ultra DMA timing table *//* mode: 0 1 2 3 4 5 */static const u32 udma_tcycmin[] = { 112, 73, 54, 39, 25, 17 };static const u32 udma_tdvsmin[] = { 70, 48, 31, 20, 7, 5 };static const u32 udma_tenvmax[] = { 70, 70, 70, 55, 55, 50 };static const u32 udma_trpmin[] = { 160, 125, 100, 100, 100, 85 };static const u32 udma_tmin[] = { 5, 5, 5, 5, 3, 3 };static const u32 udma_tmlimin = 20;static const u32 udma_tzahmin = 20;static const u32 udma_tenvmin = 20;static const u32 udma_tackmin = 20;static const u32 udma_tssmin = 50;/** * * Function: num_clocks_min * * Description: * calculate number of SCLK cycles to meet minimum timing */static unsigned short num_clocks_min(unsigned long tmin, unsigned long fsclk){ unsigned long tmp ; unsigned short result; tmp = tmin * (fsclk/1000/1000) / 1000; result = (unsigned short)tmp; if ((tmp*1000*1000) < (tmin*(fsclk/1000))) { result++; } return result;}/** * bfin_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um * * Set PIO mode for device. * * LOCKING: * None (inherited from caller). */static void bfin_set_piomode(struct ata_port *ap, struct ata_device *adev){ int mode = adev->pio_mode - XFER_PIO_0; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; unsigned int fsclk = get_sclk(); unsigned short teoc_reg, t2_reg, teoc_pio; unsigned short t4_reg, t2_pio, t1_reg; unsigned short n0, n6, t6min = 5; /* the most restrictive timing value is t6 and tc, the DIOW - data hold * If one SCLK pulse is longer than this minimum value then register * transfers cannot be supported at this frequency. */ n6 = num_clocks_min(t6min, fsclk); if (mode >= 0 && mode <= 4 && n6 >= 1) { pr_debug("set piomode: mode=%d, fsclk=%ud\n", mode, fsclk); /* calculate the timing values for register transfers. */ while (mode > 0 && pio_fsclk[mode] > fsclk) mode--; /* DIOR/DIOW to end cycle time */ t2_reg = num_clocks_min(reg_t2min[mode], fsclk); /* DIOR/DIOW asserted pulse width */ teoc_reg = num_clocks_min(reg_teocmin[mode], fsclk); /* Cycle Time */ n0 = num_clocks_min(reg_t0min[mode], fsclk); /* increase t2 until we meed the minimum cycle length */ if (t2_reg + teoc_reg < n0) t2_reg = n0 - teoc_reg; /* calculate the timing values for pio transfers. */ /* DIOR/DIOW to end cycle time */ t2_pio = num_clocks_min(pio_t2min[mode], fsclk); /* DIOR/DIOW asserted pulse width */ teoc_pio = num_clocks_min(pio_teocmin[mode], fsclk); /* Cycle Time */ n0 = num_clocks_min(pio_t0min[mode], fsclk); /* increase t2 until we meed the minimum cycle length */ if (t2_pio + teoc_pio < n0) t2_pio = n0 - teoc_pio; /* Address valid to DIOR/DIORW */ t1_reg = num_clocks_min(pio_t1min[mode], fsclk); /* DIOW data hold */ t4_reg = num_clocks_min(pio_t4min[mode], fsclk); ATAPI_SET_REG_TIM_0(base, (teoc_reg<<8 | t2_reg)); ATAPI_SET_PIO_TIM_0(base, (t4_reg<<12 | t2_pio<<4 | t1_reg)); ATAPI_SET_PIO_TIM_1(base, teoc_pio); if (mode > 2) { ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) | IORDY_EN); } else { ATAPI_SET_CONTROL(base, ATAPI_GET_CONTROL(base) & ~IORDY_EN); } /* Disable host ATAPI PIO interrupts */ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) & ~(PIO_DONE_MASK | HOST_TERM_XFER_MASK)); SSYNC(); }}/** * bfin_set_dmamode - Initialize host controller PATA DMA timings * @ap: Port whose timings we are configuring * @adev: um * @udma: udma mode, 0 - 6 * * Set UDMA mode for device. * * LOCKING: * None (inherited from caller). */static void bfin_set_dmamode(struct ata_port *ap, struct ata_device *adev){ int mode; void __iomem *base = (void __iomem *)ap->ioaddr.ctl_addr; unsigned long fsclk = get_sclk(); unsigned short tenv, tack, tcyc_tdvs, tdvs, tmli, tss, trp, tzah; unsigned short tm, td, tkr, tkw, teoc, th; unsigned short n0, nf, tfmin = 5; unsigned short nmin, tcyc; mode = adev->dma_mode - XFER_UDMA_0; if (mode >= 0 && mode <= 5) { pr_debug("set udmamode: mode=%d\n", mode); /* the most restrictive timing value is t6 and tc, * the DIOW - data hold. If one SCLK pulse is longer * than this minimum value then register * transfers cannot be supported at this frequency. */ while (mode > 0 && udma_fsclk[mode] > fsclk) mode--; nmin = num_clocks_min(udma_tmin[mode], fsclk); if (nmin >= 1) { /* calculate the timing values for Ultra DMA. */ tdvs = num_clocks_min(udma_tdvsmin[mode], fsclk); tcyc = num_clocks_min(udma_tcycmin[mode], fsclk); tcyc_tdvs = 2; /* increase tcyc - tdvs (tcyc_tdvs) until we meed * the minimum cycle length */ if (tdvs + tcyc_tdvs < tcyc) tcyc_tdvs = tcyc - tdvs; /* Mow assign the values required for the timing * registers */ if (tcyc_tdvs < 2) tcyc_tdvs = 2; if (tdvs < 2) tdvs = 2; tack = num_clocks_min(udma_tackmin, fsclk); tss = num_clocks_min(udma_tssmin, fsclk); tmli = num_clocks_min(udma_tmlimin, fsclk); tzah = num_clocks_min(udma_tzahmin, fsclk); trp = num_clocks_min(udma_trpmin[mode], fsclk); tenv = num_clocks_min(udma_tenvmin, fsclk); if (tenv <= udma_tenvmax[mode]) { ATAPI_SET_ULTRA_TIM_0(base, (tenv<<8 | tack)); ATAPI_SET_ULTRA_TIM_1(base, (tcyc_tdvs<<8 | tdvs)); ATAPI_SET_ULTRA_TIM_2(base, (tmli<<8 | tss)); ATAPI_SET_ULTRA_TIM_3(base, (trp<<8 | tzah)); /* Enable host ATAPI Untra DMA interrupts */ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) | UDMAIN_DONE_MASK | UDMAOUT_DONE_MASK | UDMAIN_TERM_MASK | UDMAOUT_TERM_MASK); } } } mode = adev->dma_mode - XFER_MW_DMA_0; if (mode >= 0 && mode <= 2) { pr_debug("set mdmamode: mode=%d\n", mode); /* the most restrictive timing value is tf, the DMACK to * read data released. If one SCLK pulse is longer than * this maximum value then the MDMA mode * cannot be supported at this frequency. */ while (mode > 0 && mdma_fsclk[mode] > fsclk) mode--; nf = num_clocks_min(tfmin, fsclk); if (nf >= 1) { /* calculate the timing values for Multi-word DMA. */ /* DIOR/DIOW asserted pulse width */ td = num_clocks_min(mdma_tdmin[mode], fsclk); /* DIOR negated pulse width */ tkw = num_clocks_min(mdma_tkwmin[mode], fsclk); /* Cycle Time */ n0 = num_clocks_min(mdma_t0min[mode], fsclk); /* increase tk until we meed the minimum cycle length */ if (tkw + td < n0) tkw = n0 - td; /* DIOR negated pulse width - read */ tkr = num_clocks_min(mdma_tkrmin[mode], fsclk); /* CS{1:0] valid to DIOR/DIOW */ tm = num_clocks_min(mdma_tmmin[mode], fsclk); /* DIOR/DIOW to DMACK hold */ teoc = num_clocks_min(mdma_tjmin[mode], fsclk); /* DIOW Data hold */ th = num_clocks_min(mdma_thmin[mode], fsclk); ATAPI_SET_MULTI_TIM_0(base, (tm<<8 | td)); ATAPI_SET_MULTI_TIM_1(base, (tkr<<8 | tkw)); ATAPI_SET_MULTI_TIM_2(base, (teoc<<8 | th)); /* Enable host ATAPI Multi DMA interrupts */ ATAPI_SET_INT_MASK(base, ATAPI_GET_INT_MASK(base) | MULTI_DONE_MASK | MULTI_TERM_MASK); SSYNC(); } } return;}/** * * Function: wait_complete * * Description: Waits the interrupt from device * */static inline void wait_complete(void __iomem *base, unsigned short mask){ unsigned short status; unsigned int i = 0;#define PATA_BF54X_WAIT_TIMEOUT 10000 for (i = 0; i < PATA_BF54X_WAIT_TIMEOUT; i++) { status = ATAPI_GET_INT_STATUS(base) & mask; if (status) break; } ATAPI_SET_INT_STATUS(base, mask);}/** * * Function: write_atapi_register * * Description: Writes to ATA Device Resgister * */static void write_atapi_register(void __iomem *base, unsigned long ata_reg, unsigned short value){ /* Program the ATA_DEV_TXBUF register with write data (to be * written into the device). */ ATAPI_SET_DEV_TXBUF(base, value); /* Program the ATA_DEV_ADDR register with address of the * device register (0x01 to 0x0F). */ ATAPI_SET_DEV_ADDR(base, ata_reg); /* Program the ATA_CTRL register with dir set to write (1) */ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | XFER_DIR)); /* ensure PIO DMA is not set */ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) & ~PIO_USE_DMA)); /* and start the transfer */ ATAPI_SET_CONTROL(base, (ATAPI_GET_CONTROL(base) | PIO_START)); /* Wait for the interrupt to indicate the end of the transfer. * (We need to wait on and clear rhe ATA_DEV_INT interrupt status) */ wait_complete(base, PIO_DONE_INT);}/** *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -