18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Bestcomm ATA task driver 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Patterned after bestcomm/fec.c by Dale Farnsworth <dfarnsworth@mvista.com> 68c2ecf20Sopenharmony_ci * 2003-2004 (c) MontaVista, Software, Inc. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> 98c2ecf20Sopenharmony_ci * Copyright (C) 2006 Freescale - John Rigby 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public License 128c2ecf20Sopenharmony_ci * version 2. This program is licensed "as is" without any warranty of any 138c2ecf20Sopenharmony_ci * kind, whether express or implied. 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include <asm/io.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/fsl/bestcomm/bestcomm.h> 228c2ecf20Sopenharmony_ci#include <linux/fsl/bestcomm/bestcomm_priv.h> 238c2ecf20Sopenharmony_ci#include <linux/fsl/bestcomm/ata.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* ======================================================================== */ 278c2ecf20Sopenharmony_ci/* Task image/var/inc */ 288c2ecf20Sopenharmony_ci/* ======================================================================== */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* ata task image */ 318c2ecf20Sopenharmony_ciextern u32 bcom_ata_task[]; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* ata task vars that need to be set before enabling the task */ 348c2ecf20Sopenharmony_cistruct bcom_ata_var { 358c2ecf20Sopenharmony_ci u32 enable; /* (u16*) address of task's control register */ 368c2ecf20Sopenharmony_ci u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */ 378c2ecf20Sopenharmony_ci u32 bd_last; /* (struct bcom_bd*) end of ring buffer */ 388c2ecf20Sopenharmony_ci u32 bd_start; /* (struct bcom_bd*) current bd */ 398c2ecf20Sopenharmony_ci u32 buffer_size; /* size of receive buffer */ 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* ata task incs that need to be set before enabling the task */ 438c2ecf20Sopenharmony_cistruct bcom_ata_inc { 448c2ecf20Sopenharmony_ci u16 pad0; 458c2ecf20Sopenharmony_ci s16 incr_bytes; 468c2ecf20Sopenharmony_ci u16 pad1; 478c2ecf20Sopenharmony_ci s16 incr_dst; 488c2ecf20Sopenharmony_ci u16 pad2; 498c2ecf20Sopenharmony_ci s16 incr_src; 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/* ======================================================================== */ 548c2ecf20Sopenharmony_ci/* Task support code */ 558c2ecf20Sopenharmony_ci/* ======================================================================== */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistruct bcom_task * 588c2ecf20Sopenharmony_cibcom_ata_init(int queue_len, int maxbufsize) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct bcom_task *tsk; 618c2ecf20Sopenharmony_ci struct bcom_ata_var *var; 628c2ecf20Sopenharmony_ci struct bcom_ata_inc *inc; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ 658c2ecf20Sopenharmony_ci bcom_disable_prefetch(); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); 688c2ecf20Sopenharmony_ci if (!tsk) 698c2ecf20Sopenharmony_ci return NULL; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci tsk->flags = BCOM_FLAGS_NONE; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci bcom_ata_reset_bd(tsk); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum); 768c2ecf20Sopenharmony_ci inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (bcom_load_image(tsk->tasknum, bcom_ata_task)) { 798c2ecf20Sopenharmony_ci bcom_task_free(tsk); 808c2ecf20Sopenharmony_ci return NULL; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci var->enable = bcom_eng->regs_base + 848c2ecf20Sopenharmony_ci offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]); 858c2ecf20Sopenharmony_ci var->bd_base = tsk->bd_pa; 868c2ecf20Sopenharmony_ci var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size); 878c2ecf20Sopenharmony_ci var->bd_start = tsk->bd_pa; 888c2ecf20Sopenharmony_ci var->buffer_size = maxbufsize; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci /* Configure some stuff */ 918c2ecf20Sopenharmony_ci bcom_set_task_pragma(tsk->tasknum, BCOM_ATA_PRAGMA); 928c2ecf20Sopenharmony_ci bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX); 958c2ecf20Sopenharmony_ci out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */ 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return tsk; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_init); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_civoid bcom_ata_rx_prepare(struct bcom_task *tsk) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct bcom_ata_inc *inc; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci inc->incr_bytes = -(s16)sizeof(u32); 1108c2ecf20Sopenharmony_ci inc->incr_src = 0; 1118c2ecf20Sopenharmony_ci inc->incr_dst = sizeof(u32); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_RX); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_rx_prepare); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_civoid bcom_ata_tx_prepare(struct bcom_task *tsk) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct bcom_ata_inc *inc; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci inc->incr_bytes = -(s16)sizeof(u32); 1248c2ecf20Sopenharmony_ci inc->incr_src = sizeof(u32); 1258c2ecf20Sopenharmony_ci inc->incr_dst = 0; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_TX); 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_tx_prepare); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_civoid bcom_ata_reset_bd(struct bcom_task *tsk) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct bcom_ata_var *var; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Reset all BD */ 1368c2ecf20Sopenharmony_ci memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci tsk->index = 0; 1398c2ecf20Sopenharmony_ci tsk->outdex = 0; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum); 1428c2ecf20Sopenharmony_ci var->bd_start = var->bd_base; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_reset_bd); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_civoid bcom_ata_release(struct bcom_task *tsk) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci /* Nothing special for the ATA tasks */ 1498c2ecf20Sopenharmony_ci bcom_task_free(tsk); 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_release); 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BestComm ATA task driver"); 1558c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Rigby"); 1568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1578c2ecf20Sopenharmony_ci 158