162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Bestcomm ATA task driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Patterned after bestcomm/fec.c by Dale Farnsworth <dfarnsworth@mvista.com> 662306a36Sopenharmony_ci * 2003-2004 (c) MontaVista, Software, Inc. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2006-2007 Sylvain Munaut <tnt@246tNt.com> 962306a36Sopenharmony_ci * Copyright (C) 2006 Freescale - John Rigby 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/types.h> 1562306a36Sopenharmony_ci#include <asm/io.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/fsl/bestcomm/bestcomm.h> 1862306a36Sopenharmony_ci#include <linux/fsl/bestcomm/bestcomm_priv.h> 1962306a36Sopenharmony_ci#include <linux/fsl/bestcomm/ata.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* ======================================================================== */ 2362306a36Sopenharmony_ci/* Task image/var/inc */ 2462306a36Sopenharmony_ci/* ======================================================================== */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* ata task image */ 2762306a36Sopenharmony_ciextern u32 bcom_ata_task[]; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* ata task vars that need to be set before enabling the task */ 3062306a36Sopenharmony_cistruct bcom_ata_var { 3162306a36Sopenharmony_ci u32 enable; /* (u16*) address of task's control register */ 3262306a36Sopenharmony_ci u32 bd_base; /* (struct bcom_bd*) beginning of ring buffer */ 3362306a36Sopenharmony_ci u32 bd_last; /* (struct bcom_bd*) end of ring buffer */ 3462306a36Sopenharmony_ci u32 bd_start; /* (struct bcom_bd*) current bd */ 3562306a36Sopenharmony_ci u32 buffer_size; /* size of receive buffer */ 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* ata task incs that need to be set before enabling the task */ 3962306a36Sopenharmony_cistruct bcom_ata_inc { 4062306a36Sopenharmony_ci u16 pad0; 4162306a36Sopenharmony_ci s16 incr_bytes; 4262306a36Sopenharmony_ci u16 pad1; 4362306a36Sopenharmony_ci s16 incr_dst; 4462306a36Sopenharmony_ci u16 pad2; 4562306a36Sopenharmony_ci s16 incr_src; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* ======================================================================== */ 5062306a36Sopenharmony_ci/* Task support code */ 5162306a36Sopenharmony_ci/* ======================================================================== */ 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistruct bcom_task * 5462306a36Sopenharmony_cibcom_ata_init(int queue_len, int maxbufsize) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct bcom_task *tsk; 5762306a36Sopenharmony_ci struct bcom_ata_var *var; 5862306a36Sopenharmony_ci struct bcom_ata_inc *inc; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* Prefetch breaks ATA DMA. Turn it off for ATA DMA */ 6162306a36Sopenharmony_ci bcom_disable_prefetch(); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci tsk = bcom_task_alloc(queue_len, sizeof(struct bcom_ata_bd), 0); 6462306a36Sopenharmony_ci if (!tsk) 6562306a36Sopenharmony_ci return NULL; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci tsk->flags = BCOM_FLAGS_NONE; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci bcom_ata_reset_bd(tsk); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum); 7262306a36Sopenharmony_ci inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (bcom_load_image(tsk->tasknum, bcom_ata_task)) { 7562306a36Sopenharmony_ci bcom_task_free(tsk); 7662306a36Sopenharmony_ci return NULL; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci var->enable = bcom_eng->regs_base + 8062306a36Sopenharmony_ci offsetof(struct mpc52xx_sdma, tcr[tsk->tasknum]); 8162306a36Sopenharmony_ci var->bd_base = tsk->bd_pa; 8262306a36Sopenharmony_ci var->bd_last = tsk->bd_pa + ((tsk->num_bd-1) * tsk->bd_size); 8362306a36Sopenharmony_ci var->bd_start = tsk->bd_pa; 8462306a36Sopenharmony_ci var->buffer_size = maxbufsize; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci /* Configure some stuff */ 8762306a36Sopenharmony_ci bcom_set_task_pragma(tsk->tasknum, BCOM_ATA_PRAGMA); 8862306a36Sopenharmony_ci bcom_set_task_auto_start(tsk->tasknum, tsk->tasknum); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_RX], BCOM_IPR_ATA_RX); 9162306a36Sopenharmony_ci out_8(&bcom_eng->regs->ipr[BCOM_INITIATOR_ATA_TX], BCOM_IPR_ATA_TX); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci out_be32(&bcom_eng->regs->IntPend, 1<<tsk->tasknum); /* Clear ints */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci return tsk; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_init); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_civoid bcom_ata_rx_prepare(struct bcom_task *tsk) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct bcom_ata_inc *inc; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci inc->incr_bytes = -(s16)sizeof(u32); 10662306a36Sopenharmony_ci inc->incr_src = 0; 10762306a36Sopenharmony_ci inc->incr_dst = sizeof(u32); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_RX); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_rx_prepare); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_civoid bcom_ata_tx_prepare(struct bcom_task *tsk) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct bcom_ata_inc *inc; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci inc = (struct bcom_ata_inc *) bcom_task_inc(tsk->tasknum); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci inc->incr_bytes = -(s16)sizeof(u32); 12062306a36Sopenharmony_ci inc->incr_src = sizeof(u32); 12162306a36Sopenharmony_ci inc->incr_dst = 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci bcom_set_initiator(tsk->tasknum, BCOM_INITIATOR_ATA_TX); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_tx_prepare); 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_civoid bcom_ata_reset_bd(struct bcom_task *tsk) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci struct bcom_ata_var *var; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci /* Reset all BD */ 13262306a36Sopenharmony_ci memset_io(tsk->bd, 0x00, tsk->num_bd * tsk->bd_size); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci tsk->index = 0; 13562306a36Sopenharmony_ci tsk->outdex = 0; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci var = (struct bcom_ata_var *) bcom_task_var(tsk->tasknum); 13862306a36Sopenharmony_ci var->bd_start = var->bd_base; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_reset_bd); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_civoid bcom_ata_release(struct bcom_task *tsk) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci /* Nothing special for the ATA tasks */ 14562306a36Sopenharmony_ci bcom_task_free(tsk); 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bcom_ata_release); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ciMODULE_DESCRIPTION("BestComm ATA task driver"); 15162306a36Sopenharmony_ciMODULE_AUTHOR("John Rigby"); 15262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 153