11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds *
31da177e4SLinus Torvalds * tp3780i.c -- board driver for 3780i on ThinkPads
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds *
61da177e4SLinus Torvalds * Written By: Mike Sullivan IBM Corporation
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Copyright (C) 1999 IBM Corporation
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify
111da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by
121da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
131da177e4SLinus Torvalds * (at your option) any later version.
141da177e4SLinus Torvalds *
151da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful,
161da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
171da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
181da177e4SLinus Torvalds * GNU General Public License for more details.
191da177e4SLinus Torvalds *
201da177e4SLinus Torvalds * NO WARRANTY
211da177e4SLinus Torvalds * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
221da177e4SLinus Torvalds * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
231da177e4SLinus Torvalds * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
241da177e4SLinus Torvalds * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
251da177e4SLinus Torvalds * solely responsible for determining the appropriateness of using and
261da177e4SLinus Torvalds * distributing the Program and assumes all risks associated with its
271da177e4SLinus Torvalds * exercise of rights under this Agreement, including but not limited to
281da177e4SLinus Torvalds * the risks and costs of program errors, damage to or loss of data,
291da177e4SLinus Torvalds * programs or equipment, and unavailability or interruption of operations.
301da177e4SLinus Torvalds *
311da177e4SLinus Torvalds * DISCLAIMER OF LIABILITY
321da177e4SLinus Torvalds * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
331da177e4SLinus Torvalds * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
341da177e4SLinus Torvalds * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
351da177e4SLinus Torvalds * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
361da177e4SLinus Torvalds * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
371da177e4SLinus Torvalds * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
381da177e4SLinus Torvalds * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
391da177e4SLinus Torvalds *
401da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License
411da177e4SLinus Torvalds * along with this program; if not, write to the Free Software
421da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
431da177e4SLinus Torvalds *
441da177e4SLinus Torvalds *
451da177e4SLinus Torvalds * 10/23/2000 - Alpha Release
461da177e4SLinus Torvalds * First release to the public
471da177e4SLinus Torvalds */
481da177e4SLinus Torvalds
491da177e4SLinus Torvalds #include <linux/interrupt.h>
501da177e4SLinus Torvalds #include <linux/kernel.h>
511da177e4SLinus Torvalds #include <linux/ptrace.h>
521da177e4SLinus Torvalds #include <linux/ioport.h>
531da177e4SLinus Torvalds #include <asm/io.h>
541da177e4SLinus Torvalds #include "smapi.h"
551da177e4SLinus Torvalds #include "mwavedd.h"
561da177e4SLinus Torvalds #include "tp3780i.h"
571da177e4SLinus Torvalds #include "3780i.h"
581da177e4SLinus Torvalds #include "mwavepub.h"
591da177e4SLinus Torvalds
601da177e4SLinus Torvalds static unsigned short s_ausThinkpadIrqToField[16] =
611da177e4SLinus Torvalds { 0xFFFF, 0xFFFF, 0xFFFF, 0x0001, 0x0002, 0x0003, 0xFFFF, 0x0004,
621da177e4SLinus Torvalds 0xFFFF, 0xFFFF, 0x0005, 0x0006, 0xFFFF, 0xFFFF, 0xFFFF, 0x0007 };
631da177e4SLinus Torvalds static unsigned short s_ausThinkpadDmaToField[8] =
641da177e4SLinus Torvalds { 0x0001, 0x0002, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0003, 0x0004 };
651da177e4SLinus Torvalds static unsigned short s_numIrqs = 16, s_numDmas = 8;
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds
EnableSRAM(THINKPAD_BD_DATA * pBDData)681da177e4SLinus Torvalds static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
691da177e4SLinus Torvalds {
701da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
711da177e4SLinus Torvalds unsigned short usDspBaseIO = pSettings->usDspBaseIO;
721da177e4SLinus Torvalds DSP_GPIO_OUTPUT_DATA_15_8 rGpioOutputData;
731da177e4SLinus Torvalds DSP_GPIO_DRIVER_ENABLE_15_8 rGpioDriverEnable;
741da177e4SLinus Torvalds DSP_GPIO_MODE_15_8 rGpioMode;
751da177e4SLinus Torvalds
761da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM, entry\n");
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds MKWORD(rGpioMode) = ReadMsaCfg(DSP_GpioModeControl_15_8);
791da177e4SLinus Torvalds rGpioMode.GpioMode10 = 0;
801da177e4SLinus Torvalds WriteMsaCfg(DSP_GpioModeControl_15_8, MKWORD(rGpioMode));
811da177e4SLinus Torvalds
821da177e4SLinus Torvalds MKWORD(rGpioDriverEnable) = 0;
8326ec99b1SArnd Bergmann rGpioDriverEnable.Enable10 = true;
8426ec99b1SArnd Bergmann rGpioDriverEnable.Mask10 = true;
851da177e4SLinus Torvalds WriteMsaCfg(DSP_GpioDriverEnable_15_8, MKWORD(rGpioDriverEnable));
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds MKWORD(rGpioOutputData) = 0;
881da177e4SLinus Torvalds rGpioOutputData.Latch10 = 0;
8926ec99b1SArnd Bergmann rGpioOutputData.Mask10 = true;
901da177e4SLinus Torvalds WriteMsaCfg(DSP_GpioOutputData_15_8, MKWORD(rGpioOutputData));
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I, "tp3780i::EnableSRAM exit\n");
931da177e4SLinus Torvalds }
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds
UartInterrupt(int irq,void * dev_id)967d12e780SDavid Howells static irqreturn_t UartInterrupt(int irq, void *dev_id)
971da177e4SLinus Torvalds {
981da177e4SLinus Torvalds PRINTK_3(TRACE_TP3780I,
990d626239SJeff Garzik "tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id);
1001da177e4SLinus Torvalds return IRQ_HANDLED;
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds
DspInterrupt(int irq,void * dev_id)1037d12e780SDavid Howells static irqreturn_t DspInterrupt(int irq, void *dev_id)
1041da177e4SLinus Torvalds {
1051da177e4SLinus Torvalds pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
1061da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings;
1071da177e4SLinus Torvalds unsigned short usDspBaseIO = pSettings->usDspBaseIO;
1081da177e4SLinus Torvalds unsigned short usIPCSource = 0, usIsolationMask, usPCNum;
1091da177e4SLinus Torvalds
1101da177e4SLinus Torvalds PRINTK_3(TRACE_TP3780I,
1110d626239SJeff Garzik "tp3780i::DspInterrupt entry irq %x dev_id %p\n", irq, dev_id);
1121da177e4SLinus Torvalds
1131da177e4SLinus Torvalds if (dsp3780I_GetIPCSource(usDspBaseIO, &usIPCSource) == 0) {
1141da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
1151da177e4SLinus Torvalds "tp3780i::DspInterrupt, return from dsp3780i_GetIPCSource, usIPCSource %x\n",
1161da177e4SLinus Torvalds usIPCSource);
1171da177e4SLinus Torvalds usIsolationMask = 1;
1181da177e4SLinus Torvalds for (usPCNum = 1; usPCNum <= 16; usPCNum++) {
1191da177e4SLinus Torvalds if (usIPCSource & usIsolationMask) {
1201da177e4SLinus Torvalds usIPCSource &= ~usIsolationMask;
1211da177e4SLinus Torvalds PRINTK_3(TRACE_TP3780I,
1221da177e4SLinus Torvalds "tp3780i::DspInterrupt usPCNum %x usIPCSource %x\n",
1231da177e4SLinus Torvalds usPCNum, usIPCSource);
1241da177e4SLinus Torvalds if (pDrvData->IPCs[usPCNum - 1].usIntCount == 0) {
1251da177e4SLinus Torvalds pDrvData->IPCs[usPCNum - 1].usIntCount = 1;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
1281da177e4SLinus Torvalds "tp3780i::DspInterrupt usIntCount %x\n",
1291da177e4SLinus Torvalds pDrvData->IPCs[usPCNum - 1].usIntCount);
13026ec99b1SArnd Bergmann if (pDrvData->IPCs[usPCNum - 1].bIsEnabled == true) {
1311da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
1321da177e4SLinus Torvalds "tp3780i::DspInterrupt, waking up usPCNum %x\n",
1331da177e4SLinus Torvalds usPCNum - 1);
1341da177e4SLinus Torvalds wake_up_interruptible(&pDrvData->IPCs[usPCNum - 1].ipc_wait_queue);
1351da177e4SLinus Torvalds } else {
1361da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
1371da177e4SLinus Torvalds "tp3780i::DspInterrupt, no one waiting for IPC %x\n",
1381da177e4SLinus Torvalds usPCNum - 1);
1391da177e4SLinus Torvalds }
1401da177e4SLinus Torvalds }
1411da177e4SLinus Torvalds if (usIPCSource == 0)
1421da177e4SLinus Torvalds break;
1431da177e4SLinus Torvalds /* try next IPC */
1441da177e4SLinus Torvalds usIsolationMask = usIsolationMask << 1;
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds } else {
1471da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I,
1481da177e4SLinus Torvalds "tp3780i::DspInterrupt, return false from dsp3780i_GetIPCSource\n");
1491da177e4SLinus Torvalds }
1501da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I, "tp3780i::DspInterrupt exit\n");
1511da177e4SLinus Torvalds return IRQ_HANDLED;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds
tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData)1551da177e4SLinus Torvalds int tp3780I_InitializeBoardData(THINKPAD_BD_DATA * pBDData)
1561da177e4SLinus Torvalds {
1571da177e4SLinus Torvalds int retval = 0;
1581da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
1591da177e4SLinus Torvalds
1601da177e4SLinus Torvalds
1611da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData entry pBDData %p\n", pBDData);
1621da177e4SLinus Torvalds
16326ec99b1SArnd Bergmann pBDData->bDSPEnabled = false;
16426ec99b1SArnd Bergmann pSettings->bInterruptClaimed = false;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds retval = smapi_init();
1671da177e4SLinus Torvalds if (retval) {
1681da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_InitializeBoardData: Error: SMAPI is not available on this machine\n");
1691da177e4SLinus Torvalds } else {
1701da177e4SLinus Torvalds if (mwave_3780i_irq || mwave_3780i_io || mwave_uart_irq || mwave_uart_io) {
1711da177e4SLinus Torvalds retval = smapi_set_DSP_cfg();
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds
1751da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_InitializeBoardData exit retval %x\n", retval);
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds return retval;
1781da177e4SLinus Torvalds }
1791da177e4SLinus Torvalds
tp3780I_Cleanup(THINKPAD_BD_DATA * pBDData)180f6d706ddSYang Li void tp3780I_Cleanup(THINKPAD_BD_DATA *pBDData)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
1831da177e4SLinus Torvalds "tp3780i::tp3780I_Cleanup entry and exit pBDData %p\n", pBDData);
1841da177e4SLinus Torvalds }
1851da177e4SLinus Torvalds
tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData)1861da177e4SLinus Torvalds int tp3780I_CalcResources(THINKPAD_BD_DATA * pBDData)
1871da177e4SLinus Torvalds {
1881da177e4SLinus Torvalds SMAPI_DSP_SETTINGS rSmapiInfo;
1891da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
1921da177e4SLinus Torvalds "tp3780i::tp3780I_CalcResources entry pBDData %p\n", pBDData);
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds if (smapi_query_DSP_cfg(&rSmapiInfo)) {
1951da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_CalcResources: Error: Could not query DSP config. Aborting.\n");
1961da177e4SLinus Torvalds return -EIO;
1971da177e4SLinus Torvalds }
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds /* Sanity check */
2001da177e4SLinus Torvalds if (
2011da177e4SLinus Torvalds ( rSmapiInfo.usDspIRQ == 0 )
2021da177e4SLinus Torvalds || ( rSmapiInfo.usDspBaseIO == 0 )
2031da177e4SLinus Torvalds || ( rSmapiInfo.usUartIRQ == 0 )
2041da177e4SLinus Torvalds || ( rSmapiInfo.usUartBaseIO == 0 )
2051da177e4SLinus Torvalds ) {
2061da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_CalcResources: Error: Illegal resource setting. Aborting.\n");
2071da177e4SLinus Torvalds return -EIO;
2081da177e4SLinus Torvalds }
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds pSettings->bDSPEnabled = (rSmapiInfo.bDSPEnabled && rSmapiInfo.bDSPPresent);
2111da177e4SLinus Torvalds pSettings->bModemEnabled = rSmapiInfo.bModemEnabled;
2121da177e4SLinus Torvalds pSettings->usDspIrq = rSmapiInfo.usDspIRQ;
2131da177e4SLinus Torvalds pSettings->usDspDma = rSmapiInfo.usDspDMA;
2141da177e4SLinus Torvalds pSettings->usDspBaseIO = rSmapiInfo.usDspBaseIO;
2151da177e4SLinus Torvalds pSettings->usUartIrq = rSmapiInfo.usUartIRQ;
2161da177e4SLinus Torvalds pSettings->usUartBaseIO = rSmapiInfo.usUartBaseIO;
2171da177e4SLinus Torvalds
2181da177e4SLinus Torvalds pSettings->uDStoreSize = TP_ABILITIES_DATA_SIZE;
2191da177e4SLinus Torvalds pSettings->uIStoreSize = TP_ABILITIES_INST_SIZE;
2201da177e4SLinus Torvalds pSettings->uIps = TP_ABILITIES_INTS_PER_SEC;
2211da177e4SLinus Torvalds
2221da177e4SLinus Torvalds if (pSettings->bDSPEnabled && pSettings->bModemEnabled && pSettings->usDspIrq == pSettings->usUartIrq) {
2231da177e4SLinus Torvalds pBDData->bShareDspIrq = pBDData->bShareUartIrq = 1;
2241da177e4SLinus Torvalds } else {
2251da177e4SLinus Torvalds pBDData->bShareDspIrq = pBDData->bShareUartIrq = 0;
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds
2281da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_CalcResources exit\n");
2291da177e4SLinus Torvalds
2301da177e4SLinus Torvalds return 0;
2311da177e4SLinus Torvalds }
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds
tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)2341da177e4SLinus Torvalds int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)
2351da177e4SLinus Torvalds {
2361da177e4SLinus Torvalds int retval = 0;
2371da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
2381da177e4SLinus Torvalds struct resource *pres;
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
2411da177e4SLinus Torvalds "tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData);
2421da177e4SLinus Torvalds
2431da177e4SLinus Torvalds pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
2441da177e4SLinus Torvalds if ( pres == NULL ) retval = -EIO;
245c97f97b3SAdrian Bunk
2461da177e4SLinus Torvalds if (retval) {
2471da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO);
2481da177e4SLinus Torvalds retval = -EIO;
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds
2511da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ClaimResources exit retval %x\n", retval);
2521da177e4SLinus Torvalds
2531da177e4SLinus Torvalds return retval;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds
tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)2561da177e4SLinus Torvalds int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
2571da177e4SLinus Torvalds {
2581da177e4SLinus Torvalds int retval = 0;
2591da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
2601da177e4SLinus Torvalds
2611da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
2621da177e4SLinus Torvalds "tp3780i::tp3780I_ReleaseResources entry pBDData %p\n", pBDData);
2631da177e4SLinus Torvalds
2641da177e4SLinus Torvalds release_region(pSettings->usDspBaseIO & (~3), 16);
2651da177e4SLinus Torvalds
2661da177e4SLinus Torvalds if (pSettings->bInterruptClaimed) {
2671da177e4SLinus Torvalds free_irq(pSettings->usDspIrq, NULL);
26826ec99b1SArnd Bergmann pSettings->bInterruptClaimed = false;
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds
2711da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
2721da177e4SLinus Torvalds "tp3780i::tp3780I_ReleaseResources exit retval %x\n", retval);
2731da177e4SLinus Torvalds
2741da177e4SLinus Torvalds return retval;
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds
2771da177e4SLinus Torvalds
2781da177e4SLinus Torvalds
tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)2791da177e4SLinus Torvalds int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
2801da177e4SLinus Torvalds {
2811da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
28226ec99b1SArnd Bergmann bool bDSPPoweredUp = false, bInterruptAllocated = false;
2831da177e4SLinus Torvalds
2841da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
2851da177e4SLinus Torvalds
2861da177e4SLinus Torvalds if (pBDData->bDSPEnabled) {
2871da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: DSP already enabled!\n");
2881da177e4SLinus Torvalds goto exit_cleanup;
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds
2911da177e4SLinus Torvalds if (!pSettings->bDSPEnabled) {
2921da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780::tp3780I_EnableDSP: Error: pSettings->bDSPEnabled not set\n");
2931da177e4SLinus Torvalds goto exit_cleanup;
2941da177e4SLinus Torvalds }
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds if (
2971da177e4SLinus Torvalds (pSettings->usDspIrq >= s_numIrqs)
2981da177e4SLinus Torvalds || (pSettings->usDspDma >= s_numDmas)
2991da177e4SLinus Torvalds || (s_ausThinkpadIrqToField[pSettings->usDspIrq] == 0xFFFF)
3001da177e4SLinus Torvalds || (s_ausThinkpadDmaToField[pSettings->usDspDma] == 0xFFFF)
3011da177e4SLinus Torvalds ) {
3021da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: invalid irq %x\n", pSettings->usDspIrq);
3031da177e4SLinus Torvalds goto exit_cleanup;
3041da177e4SLinus Torvalds }
3051da177e4SLinus Torvalds
3061da177e4SLinus Torvalds if (
3071da177e4SLinus Torvalds ((pSettings->usDspBaseIO & 0xF00F) != 0)
3081da177e4SLinus Torvalds || (pSettings->usDspBaseIO & 0x0FF0) == 0
3091da177e4SLinus Torvalds ) {
3101da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Invalid DSP base I/O address %x\n", pSettings->usDspBaseIO);
3111da177e4SLinus Torvalds goto exit_cleanup;
3121da177e4SLinus Torvalds }
3131da177e4SLinus Torvalds
3141da177e4SLinus Torvalds if (pSettings->bModemEnabled) {
3151da177e4SLinus Torvalds if (
3161da177e4SLinus Torvalds pSettings->usUartIrq >= s_numIrqs
3171da177e4SLinus Torvalds || s_ausThinkpadIrqToField[pSettings->usUartIrq] == 0xFFFF
3181da177e4SLinus Torvalds ) {
3191da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Invalid UART IRQ %x\n", pSettings->usUartIrq);
3201da177e4SLinus Torvalds goto exit_cleanup;
3211da177e4SLinus Torvalds }
3221da177e4SLinus Torvalds switch (pSettings->usUartBaseIO) {
3231da177e4SLinus Torvalds case 0x03F8:
3241da177e4SLinus Torvalds case 0x02F8:
3251da177e4SLinus Torvalds case 0x03E8:
3261da177e4SLinus Torvalds case 0x02E8:
3271da177e4SLinus Torvalds break;
3281da177e4SLinus Torvalds
3291da177e4SLinus Torvalds default:
3301da177e4SLinus Torvalds PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Invalid UART base I/O address %x\n", pSettings->usUartBaseIO);
3311da177e4SLinus Torvalds goto exit_cleanup;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds
33526ec99b1SArnd Bergmann pSettings->bDspIrqActiveLow = pSettings->bDspIrqPulse = true;
33626ec99b1SArnd Bergmann pSettings->bUartIrqActiveLow = pSettings->bUartIrqPulse = true;
3371da177e4SLinus Torvalds
3381da177e4SLinus Torvalds if (pBDData->bShareDspIrq) {
33926ec99b1SArnd Bergmann pSettings->bDspIrqActiveLow = false;
3401da177e4SLinus Torvalds }
3411da177e4SLinus Torvalds if (pBDData->bShareUartIrq) {
34226ec99b1SArnd Bergmann pSettings->bUartIrqActiveLow = false;
3431da177e4SLinus Torvalds }
3441da177e4SLinus Torvalds
3451da177e4SLinus Torvalds pSettings->usNumTransfers = TP_CFG_NumTransfers;
3461da177e4SLinus Torvalds pSettings->usReRequest = TP_CFG_RerequestTimer;
3471da177e4SLinus Torvalds pSettings->bEnableMEMCS16 = TP_CFG_MEMCS16;
3481da177e4SLinus Torvalds pSettings->usIsaMemCmdWidth = TP_CFG_IsaMemCmdWidth;
3491da177e4SLinus Torvalds pSettings->bGateIOCHRDY = TP_CFG_GateIOCHRDY;
3501da177e4SLinus Torvalds pSettings->bEnablePwrMgmt = TP_CFG_EnablePwrMgmt;
3511da177e4SLinus Torvalds pSettings->usHBusTimerLoadValue = TP_CFG_HBusTimerValue;
3521da177e4SLinus Torvalds pSettings->bDisableLBusTimeout = TP_CFG_DisableLBusTimeout;
3531da177e4SLinus Torvalds pSettings->usN_Divisor = TP_CFG_N_Divisor;
3541da177e4SLinus Torvalds pSettings->usM_Multiplier = TP_CFG_M_Multiplier;
3551da177e4SLinus Torvalds pSettings->bPllBypass = TP_CFG_PllBypass;
3561da177e4SLinus Torvalds pSettings->usChipletEnable = TP_CFG_ChipletEnable;
3571da177e4SLinus Torvalds
3580d626239SJeff Garzik if (request_irq(pSettings->usUartIrq, &UartInterrupt, 0, "mwave_uart", NULL)) {
3591da177e4SLinus Torvalds PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: Could not get UART IRQ %x\n", pSettings->usUartIrq);
3601da177e4SLinus Torvalds goto exit_cleanup;
3611da177e4SLinus Torvalds } else { /* no conflict just release */
3621da177e4SLinus Torvalds free_irq(pSettings->usUartIrq, NULL);
3631da177e4SLinus Torvalds }
3641da177e4SLinus Torvalds
3650d626239SJeff Garzik if (request_irq(pSettings->usDspIrq, &DspInterrupt, 0, "mwave_3780i", NULL)) {
3661da177e4SLinus Torvalds PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: Could not get 3780i IRQ %x\n", pSettings->usDspIrq);
3671da177e4SLinus Torvalds goto exit_cleanup;
3681da177e4SLinus Torvalds } else {
3691da177e4SLinus Torvalds PRINTK_3(TRACE_TP3780I,
3701da177e4SLinus Torvalds "tp3780i::tp3780I_EnableDSP, got interrupt %x bShareDspIrq %x\n",
3711da177e4SLinus Torvalds pSettings->usDspIrq, pBDData->bShareDspIrq);
37226ec99b1SArnd Bergmann bInterruptAllocated = true;
37326ec99b1SArnd Bergmann pSettings->bInterruptClaimed = true;
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds
37626ec99b1SArnd Bergmann smapi_set_DSP_power_state(false);
37726ec99b1SArnd Bergmann if (smapi_set_DSP_power_state(true)) {
37826ec99b1SArnd Bergmann PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_EnableDSP: Error: smapi_set_DSP_power_state(true) failed\n");
3791da177e4SLinus Torvalds goto exit_cleanup;
3801da177e4SLinus Torvalds } else {
38126ec99b1SArnd Bergmann bDSPPoweredUp = true;
3821da177e4SLinus Torvalds }
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
3851da177e4SLinus Torvalds PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n");
3861da177e4SLinus Torvalds goto exit_cleanup;
3871da177e4SLinus Torvalds }
3881da177e4SLinus Torvalds
3891da177e4SLinus Torvalds EnableSRAM(pBDData);
3901da177e4SLinus Torvalds
39126ec99b1SArnd Bergmann pBDData->bDSPEnabled = true;
3921da177e4SLinus Torvalds
3931da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP exit\n");
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds return 0;
3961da177e4SLinus Torvalds
3971da177e4SLinus Torvalds exit_cleanup:
3981da177e4SLinus Torvalds PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
3991da177e4SLinus Torvalds if (bDSPPoweredUp)
40026ec99b1SArnd Bergmann smapi_set_DSP_power_state(false);
4011da177e4SLinus Torvalds if (bInterruptAllocated) {
4021da177e4SLinus Torvalds free_irq(pSettings->usDspIrq, NULL);
40326ec99b1SArnd Bergmann pSettings->bInterruptClaimed = false;
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds return -EIO;
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds
tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)4091da177e4SLinus Torvalds int tp3780I_DisableDSP(THINKPAD_BD_DATA * pBDData)
4101da177e4SLinus Torvalds {
4111da177e4SLinus Torvalds int retval = 0;
4121da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP entry pBDData %p\n", pBDData);
4151da177e4SLinus Torvalds
4161da177e4SLinus Torvalds if (pBDData->bDSPEnabled) {
4171da177e4SLinus Torvalds dsp3780I_DisableDSP(&pBDData->rDspSettings);
4181da177e4SLinus Torvalds if (pSettings->bInterruptClaimed) {
4191da177e4SLinus Torvalds free_irq(pSettings->usDspIrq, NULL);
42026ec99b1SArnd Bergmann pSettings->bInterruptClaimed = false;
4211da177e4SLinus Torvalds }
42226ec99b1SArnd Bergmann smapi_set_DSP_power_state(false);
42326ec99b1SArnd Bergmann pBDData->bDSPEnabled = false;
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds
4261da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_DisableDSP exit retval %x\n", retval);
4271da177e4SLinus Torvalds
4281da177e4SLinus Torvalds return retval;
4291da177e4SLinus Torvalds }
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds
tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData)4321da177e4SLinus Torvalds int tp3780I_ResetDSP(THINKPAD_BD_DATA * pBDData)
4331da177e4SLinus Torvalds {
4341da177e4SLinus Torvalds int retval = 0;
4351da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ResetDSP entry pBDData %p\n",
4381da177e4SLinus Torvalds pBDData);
4391da177e4SLinus Torvalds
4401da177e4SLinus Torvalds if (dsp3780I_Reset(pSettings) == 0) {
4411da177e4SLinus Torvalds EnableSRAM(pBDData);
4421da177e4SLinus Torvalds } else {
4431da177e4SLinus Torvalds retval = -EIO;
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds
4461da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ResetDSP exit retval %x\n", retval);
4471da177e4SLinus Torvalds
4481da177e4SLinus Torvalds return retval;
4491da177e4SLinus Torvalds }
4501da177e4SLinus Torvalds
4511da177e4SLinus Torvalds
tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData)4521da177e4SLinus Torvalds int tp3780I_StartDSP(THINKPAD_BD_DATA * pBDData)
4531da177e4SLinus Torvalds {
4541da177e4SLinus Torvalds int retval = 0;
4551da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
4561da177e4SLinus Torvalds
4571da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_StartDSP entry pBDData %p\n", pBDData);
4581da177e4SLinus Torvalds
4591da177e4SLinus Torvalds if (dsp3780I_Run(pSettings) == 0) {
4601da177e4SLinus Torvalds // @BUG @TBD EnableSRAM(pBDData);
4611da177e4SLinus Torvalds } else {
4621da177e4SLinus Torvalds retval = -EIO;
4631da177e4SLinus Torvalds }
4641da177e4SLinus Torvalds
4651da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_StartDSP exit retval %x\n", retval);
4661da177e4SLinus Torvalds
4671da177e4SLinus Torvalds return retval;
4681da177e4SLinus Torvalds }
4691da177e4SLinus Torvalds
4701da177e4SLinus Torvalds
tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData,MW_ABILITIES * pAbilities)4711da177e4SLinus Torvalds int tp3780I_QueryAbilities(THINKPAD_BD_DATA * pBDData, MW_ABILITIES * pAbilities)
4721da177e4SLinus Torvalds {
4731da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
4741da177e4SLinus Torvalds "tp3780i::tp3780I_QueryAbilities entry pBDData %p\n", pBDData);
4751da177e4SLinus Torvalds
476026dadadSDan Carpenter memset(pAbilities, 0, sizeof(*pAbilities));
4771da177e4SLinus Torvalds /* fill out standard constant fields */
4781da177e4SLinus Torvalds pAbilities->instr_per_sec = pBDData->rDspSettings.uIps;
4791da177e4SLinus Torvalds pAbilities->data_size = pBDData->rDspSettings.uDStoreSize;
4801da177e4SLinus Torvalds pAbilities->inst_size = pBDData->rDspSettings.uIStoreSize;
4811da177e4SLinus Torvalds pAbilities->bus_dma_bw = pBDData->rDspSettings.uDmaBandwidth;
4821da177e4SLinus Torvalds
4831da177e4SLinus Torvalds /* fill out dynamically determined fields */
4841da177e4SLinus Torvalds pAbilities->component_list[0] = 0x00010000 | MW_ADC_MASK;
4851da177e4SLinus Torvalds pAbilities->component_list[1] = 0x00010000 | MW_ACI_MASK;
4861da177e4SLinus Torvalds pAbilities->component_list[2] = 0x00010000 | MW_AIC1_MASK;
4871da177e4SLinus Torvalds pAbilities->component_list[3] = 0x00010000 | MW_AIC2_MASK;
4881da177e4SLinus Torvalds pAbilities->component_list[4] = 0x00010000 | MW_CDDAC_MASK;
4891da177e4SLinus Torvalds pAbilities->component_list[5] = 0x00010000 | MW_MIDI_MASK;
4901da177e4SLinus Torvalds pAbilities->component_list[6] = 0x00010000 | MW_UART_MASK;
4911da177e4SLinus Torvalds pAbilities->component_count = 7;
4921da177e4SLinus Torvalds
4931da177e4SLinus Torvalds /* Fill out Mwave OS and BIOS task names */
4941da177e4SLinus Torvalds
4951da177e4SLinus Torvalds memcpy(pAbilities->mwave_os_name, TP_ABILITIES_MWAVEOS_NAME,
4961da177e4SLinus Torvalds sizeof(TP_ABILITIES_MWAVEOS_NAME));
4971da177e4SLinus Torvalds memcpy(pAbilities->bios_task_name, TP_ABILITIES_BIOSTASK_NAME,
4981da177e4SLinus Torvalds sizeof(TP_ABILITIES_BIOSTASK_NAME));
4991da177e4SLinus Torvalds
5001da177e4SLinus Torvalds PRINTK_1(TRACE_TP3780I,
5011da177e4SLinus Torvalds "tp3780i::tp3780I_QueryAbilities exit retval=SUCCESSFUL\n");
5021da177e4SLinus Torvalds
503*f8cefeadSjing yangyang return 0;
5041da177e4SLinus Torvalds }
5051da177e4SLinus Torvalds
tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData,unsigned int uOpcode,void __user * pvBuffer,unsigned int uCount,unsigned long ulDSPAddr)5061da177e4SLinus Torvalds int tp3780I_ReadWriteDspDStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
5071da177e4SLinus Torvalds void __user *pvBuffer, unsigned int uCount,
5081da177e4SLinus Torvalds unsigned long ulDSPAddr)
5091da177e4SLinus Torvalds {
5101da177e4SLinus Torvalds int retval = 0;
5111da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
5121da177e4SLinus Torvalds unsigned short usDspBaseIO = pSettings->usDspBaseIO;
51326ec99b1SArnd Bergmann bool bRC = 0;
5141da177e4SLinus Torvalds
5151da177e4SLinus Torvalds PRINTK_6(TRACE_TP3780I,
5161da177e4SLinus Torvalds "tp3780i::tp3780I_ReadWriteDspDStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
5171da177e4SLinus Torvalds pBDData, uOpcode, pvBuffer, uCount, ulDSPAddr);
5181da177e4SLinus Torvalds
5191da177e4SLinus Torvalds if (pBDData->bDSPEnabled) {
5201da177e4SLinus Torvalds switch (uOpcode) {
5211da177e4SLinus Torvalds case IOCTL_MW_READ_DATA:
5221da177e4SLinus Torvalds bRC = dsp3780I_ReadDStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
5231da177e4SLinus Torvalds break;
5241da177e4SLinus Torvalds
5251da177e4SLinus Torvalds case IOCTL_MW_READCLEAR_DATA:
5261da177e4SLinus Torvalds bRC = dsp3780I_ReadAndClearDStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
5271da177e4SLinus Torvalds break;
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds case IOCTL_MW_WRITE_DATA:
5301da177e4SLinus Torvalds bRC = dsp3780I_WriteDStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
5311da177e4SLinus Torvalds break;
5321da177e4SLinus Torvalds }
5331da177e4SLinus Torvalds }
5341da177e4SLinus Torvalds
5351da177e4SLinus Torvalds retval = (bRC) ? -EIO : 0;
5361da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_ReadWriteDspDStore exit retval %x\n", retval);
5371da177e4SLinus Torvalds
5381da177e4SLinus Torvalds return retval;
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds
5411da177e4SLinus Torvalds
tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData,unsigned int uOpcode,void __user * pvBuffer,unsigned int uCount,unsigned long ulDSPAddr)5421da177e4SLinus Torvalds int tp3780I_ReadWriteDspIStore(THINKPAD_BD_DATA * pBDData, unsigned int uOpcode,
5431da177e4SLinus Torvalds void __user *pvBuffer, unsigned int uCount,
5441da177e4SLinus Torvalds unsigned long ulDSPAddr)
5451da177e4SLinus Torvalds {
5461da177e4SLinus Torvalds int retval = 0;
5471da177e4SLinus Torvalds DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
5481da177e4SLinus Torvalds unsigned short usDspBaseIO = pSettings->usDspBaseIO;
54926ec99b1SArnd Bergmann bool bRC = 0;
5501da177e4SLinus Torvalds
5511da177e4SLinus Torvalds PRINTK_6(TRACE_TP3780I,
5521da177e4SLinus Torvalds "tp3780i::tp3780I_ReadWriteDspIStore entry pBDData %p, uOpcode %x, pvBuffer %p, uCount %x, ulDSPAddr %lx\n",
5531da177e4SLinus Torvalds pBDData, uOpcode, pvBuffer, uCount, ulDSPAddr);
5541da177e4SLinus Torvalds
5551da177e4SLinus Torvalds if (pBDData->bDSPEnabled) {
5561da177e4SLinus Torvalds switch (uOpcode) {
5571da177e4SLinus Torvalds case IOCTL_MW_READ_INST:
5581da177e4SLinus Torvalds bRC = dsp3780I_ReadIStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
5591da177e4SLinus Torvalds break;
5601da177e4SLinus Torvalds
5611da177e4SLinus Torvalds case IOCTL_MW_WRITE_INST:
5621da177e4SLinus Torvalds bRC = dsp3780I_WriteIStore(usDspBaseIO, pvBuffer, uCount, ulDSPAddr);
5631da177e4SLinus Torvalds break;
5641da177e4SLinus Torvalds }
5651da177e4SLinus Torvalds }
5661da177e4SLinus Torvalds
5671da177e4SLinus Torvalds retval = (bRC) ? -EIO : 0;
5681da177e4SLinus Torvalds
5691da177e4SLinus Torvalds PRINTK_2(TRACE_TP3780I,
5701da177e4SLinus Torvalds "tp3780i::tp3780I_ReadWriteDspIStore exit retval %x\n", retval);
5711da177e4SLinus Torvalds
5721da177e4SLinus Torvalds return retval;
5731da177e4SLinus Torvalds }
5741da177e4SLinus Torvalds
575