1800 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/******************************************************************************3 4 AudioScience HPI driver5 Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>6 7 8 Hardware Programming Interface (HPI) for AudioScience ASI6200 series adapters.9 These PCI bus adapters are based on the TI C6711 DSP.10 11 Exported functions:12 void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)13 14 #defines15 HIDE_PCI_ASSERTS to show the PCI asserts16 PROFILE_DSP2 get profile data from DSP2 if present (instead of DSP 1)17 18(C) Copyright AudioScience Inc. 1998-200319*******************************************************************************/20#define SOURCEFILE_NAME "hpi6000.c"21 22#include "hpi_internal.h"23#include "hpimsginit.h"24#include "hpidebug.h"25#include "hpi6000.h"26#include "hpidspcd.h"27#include "hpicmn.h"28 29#define HPI_HIF_BASE (0x00000200) /* start of C67xx internal RAM */30#define HPI_HIF_ADDR(member) \31 (HPI_HIF_BASE + offsetof(struct hpi_hif_6000, member))32#define HPI_HIF_ERROR_MASK 0x400033 34/* HPI6000 specific error codes */35#define HPI6000_ERROR_BASE 900 /* not actually used anywhere */36 37/* operational/messaging errors */38#define HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT 90139#define HPI6000_ERROR_RESP_GET_LEN 90240#define HPI6000_ERROR_MSG_RESP_GET_RESP_ACK 90341#define HPI6000_ERROR_MSG_GET_ADR 90442#define HPI6000_ERROR_RESP_GET_ADR 90543#define HPI6000_ERROR_MSG_RESP_BLOCKWRITE32 90644#define HPI6000_ERROR_MSG_RESP_BLOCKREAD32 90745 46#define HPI6000_ERROR_CONTROL_CACHE_PARAMS 90947 48#define HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT 91149#define HPI6000_ERROR_SEND_DATA_ACK 91250#define HPI6000_ERROR_SEND_DATA_ADR 91351#define HPI6000_ERROR_SEND_DATA_TIMEOUT 91452#define HPI6000_ERROR_SEND_DATA_CMD 91553#define HPI6000_ERROR_SEND_DATA_WRITE 91654#define HPI6000_ERROR_SEND_DATA_IDLECMD 91755 56#define HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT 92157#define HPI6000_ERROR_GET_DATA_ACK 92258#define HPI6000_ERROR_GET_DATA_CMD 92359#define HPI6000_ERROR_GET_DATA_READ 92460#define HPI6000_ERROR_GET_DATA_IDLECMD 92561 62#define HPI6000_ERROR_CONTROL_CACHE_ADDRLEN 95163#define HPI6000_ERROR_CONTROL_CACHE_READ 95264#define HPI6000_ERROR_CONTROL_CACHE_FLUSH 95365 66#define HPI6000_ERROR_MSG_RESP_GETRESPCMD 96167#define HPI6000_ERROR_MSG_RESP_IDLECMD 96268 69/* Initialisation/bootload errors */70#define HPI6000_ERROR_UNHANDLED_SUBSYS_ID 93071 72/* can't access PCI2040 */73#define HPI6000_ERROR_INIT_PCI2040 93174/* can't access DSP HPI i/f */75#define HPI6000_ERROR_INIT_DSPHPI 93276/* can't access internal DSP memory */77#define HPI6000_ERROR_INIT_DSPINTMEM 93378/* can't access SDRAM - test#1 */79#define HPI6000_ERROR_INIT_SDRAM1 93480/* can't access SDRAM - test#2 */81#define HPI6000_ERROR_INIT_SDRAM2 93582 83#define HPI6000_ERROR_INIT_VERIFY 93884 85#define HPI6000_ERROR_INIT_NOACK 93986 87#define HPI6000_ERROR_INIT_PLDTEST1 94188#define HPI6000_ERROR_INIT_PLDTEST2 94289 90/* local defines */91 92#define HIDE_PCI_ASSERTS93#define PROFILE_DSP294 95/* for PCI2040 i/f chip */96/* HPI CSR registers */97/* word offsets from CSR base */98/* use when io addresses defined as u32 * */99 100#define INTERRUPT_EVENT_SET 0101#define INTERRUPT_EVENT_CLEAR 1102#define INTERRUPT_MASK_SET 2103#define INTERRUPT_MASK_CLEAR 3104#define HPI_ERROR_REPORT 4105#define HPI_RESET 5106#define HPI_DATA_WIDTH 6107 108#define MAX_DSPS 2109/* HPI registers, spaced 8K bytes = 2K words apart */110#define DSP_SPACING 0x800111 112#define CONTROL 0x0000113#define ADDRESS 0x0200114#define DATA_AUTOINC 0x0400115#define DATA 0x0600116 117#define TIMEOUT 500000118 119struct dsp_obj {120 __iomem u32 *prHPI_control;121 __iomem u32 *prHPI_address;122 __iomem u32 *prHPI_data;123 __iomem u32 *prHPI_data_auto_inc;124 char c_dsp_rev; /*A, B */125 u32 control_cache_address_on_dsp;126 u32 control_cache_length_on_dsp;127 struct hpi_adapter_obj *pa_parent_adapter;128};129 130struct hpi_hw_obj {131 __iomem u32 *dw2040_HPICSR;132 __iomem u32 *dw2040_HPIDSP;133 134 u16 num_dsp;135 struct dsp_obj ado[MAX_DSPS];136 137 u32 message_buffer_address_on_dsp;138 u32 response_buffer_address_on_dsp;139 u32 pCI2040HPI_error_count;140 141 struct hpi_control_cache_single control_cache[HPI_NMIXER_CONTROLS];142 struct hpi_control_cache *p_cache;143};144 145static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,146 u16 dsp_index, u32 hpi_address, u32 *source, u32 count);147static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,148 u16 dsp_index, u32 hpi_address, u32 *dest, u32 count);149 150static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,151 u32 *pos_error_code);152static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,153 u16 read_or_write);154#define H6READ 1155#define H6WRITE 0156 157static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,158 struct hpi_message *phm);159static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,160 u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr);161 162static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,163 struct hpi_response *phr);164 165static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,166 u32 ack_value);167 168static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,169 u16 dsp_index, u32 host_cmd);170 171static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo);172 173static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,174 struct hpi_message *phm, struct hpi_response *phr);175 176static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,177 struct hpi_message *phm, struct hpi_response *phr);178 179static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data);180 181static u32 hpi_read_word(struct dsp_obj *pdo, u32 address);182 183static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata,184 u32 length);185 186static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,187 u32 length);188 189static void subsys_create_adapter(struct hpi_message *phm,190 struct hpi_response *phr);191 192static void adapter_delete(struct hpi_adapter_obj *pao,193 struct hpi_message *phm, struct hpi_response *phr);194 195static void adapter_get_asserts(struct hpi_adapter_obj *pao,196 struct hpi_message *phm, struct hpi_response *phr);197 198static short create_adapter_obj(struct hpi_adapter_obj *pao,199 u32 *pos_error_code);200 201static void delete_adapter_obj(struct hpi_adapter_obj *pao);202 203/* local globals */204 205static u16 gw_pci_read_asserts; /* used to count PCI2040 errors */206static u16 gw_pci_write_asserts; /* used to count PCI2040 errors */207 208static void subsys_message(struct hpi_message *phm, struct hpi_response *phr)209{210 switch (phm->function) {211 case HPI_SUBSYS_CREATE_ADAPTER:212 subsys_create_adapter(phm, phr);213 break;214 default:215 phr->error = HPI_ERROR_INVALID_FUNC;216 break;217 }218}219 220static void control_message(struct hpi_adapter_obj *pao,221 struct hpi_message *phm, struct hpi_response *phr)222{223 struct hpi_hw_obj *phw = pao->priv;224 225 switch (phm->function) {226 case HPI_CONTROL_GET_STATE:227 if (pao->has_control_cache) {228 u16 err;229 err = hpi6000_update_control_cache(pao, phm);230 231 if (err) {232 if (err >= HPI_ERROR_BACKEND_BASE) {233 phr->error =234 HPI_ERROR_CONTROL_CACHING;235 phr->specific_error = err;236 } else {237 phr->error = err;238 }239 break;240 }241 242 if (hpi_check_control_cache(phw->p_cache, phm, phr))243 break;244 }245 hw_message(pao, phm, phr);246 break;247 case HPI_CONTROL_SET_STATE:248 hw_message(pao, phm, phr);249 hpi_cmn_control_cache_sync_to_msg(phw->p_cache, phm, phr);250 break;251 252 case HPI_CONTROL_GET_INFO:253 default:254 hw_message(pao, phm, phr);255 break;256 }257}258 259static void adapter_message(struct hpi_adapter_obj *pao,260 struct hpi_message *phm, struct hpi_response *phr)261{262 switch (phm->function) {263 case HPI_ADAPTER_GET_ASSERT:264 adapter_get_asserts(pao, phm, phr);265 break;266 267 case HPI_ADAPTER_DELETE:268 adapter_delete(pao, phm, phr);269 break;270 271 default:272 hw_message(pao, phm, phr);273 break;274 }275}276 277static void outstream_message(struct hpi_adapter_obj *pao,278 struct hpi_message *phm, struct hpi_response *phr)279{280 switch (phm->function) {281 case HPI_OSTREAM_HOSTBUFFER_ALLOC:282 case HPI_OSTREAM_HOSTBUFFER_FREE:283 /* Don't let these messages go to the HW function because284 * they're called without locking the spinlock.285 * For the HPI6000 adapters the HW would return286 * HPI_ERROR_INVALID_FUNC anyway.287 */288 phr->error = HPI_ERROR_INVALID_FUNC;289 break;290 default:291 hw_message(pao, phm, phr);292 return;293 }294}295 296static void instream_message(struct hpi_adapter_obj *pao,297 struct hpi_message *phm, struct hpi_response *phr)298{299 300 switch (phm->function) {301 case HPI_ISTREAM_HOSTBUFFER_ALLOC:302 case HPI_ISTREAM_HOSTBUFFER_FREE:303 /* Don't let these messages go to the HW function because304 * they're called without locking the spinlock.305 * For the HPI6000 adapters the HW would return306 * HPI_ERROR_INVALID_FUNC anyway.307 */308 phr->error = HPI_ERROR_INVALID_FUNC;309 break;310 default:311 hw_message(pao, phm, phr);312 return;313 }314}315 316/************************************************************************/317/** HPI_6000()318 * Entry point from HPIMAN319 * All calls to the HPI start here320 */321void HPI_6000(struct hpi_message *phm, struct hpi_response *phr)322{323 struct hpi_adapter_obj *pao = NULL;324 325 if (phm->object != HPI_OBJ_SUBSYSTEM) {326 pao = hpi_find_adapter(phm->adapter_index);327 if (!pao) {328 hpi_init_response(phr, phm->object, phm->function,329 HPI_ERROR_BAD_ADAPTER_NUMBER);330 HPI_DEBUG_LOG(DEBUG, "invalid adapter index: %d \n",331 phm->adapter_index);332 return;333 }334 335 /* Don't even try to communicate with crashed DSP */336 if (pao->dsp_crashed >= 10) {337 hpi_init_response(phr, phm->object, phm->function,338 HPI_ERROR_DSP_HARDWARE);339 HPI_DEBUG_LOG(DEBUG, "adapter %d dsp crashed\n",340 phm->adapter_index);341 return;342 }343 }344 /* Init default response including the size field */345 if (phm->function != HPI_SUBSYS_CREATE_ADAPTER)346 hpi_init_response(phr, phm->object, phm->function,347 HPI_ERROR_PROCESSING_MESSAGE);348 349 switch (phm->type) {350 case HPI_TYPE_REQUEST:351 switch (phm->object) {352 case HPI_OBJ_SUBSYSTEM:353 subsys_message(phm, phr);354 break;355 356 case HPI_OBJ_ADAPTER:357 phr->size =358 sizeof(struct hpi_response_header) +359 sizeof(struct hpi_adapter_res);360 adapter_message(pao, phm, phr);361 break;362 363 case HPI_OBJ_CONTROL:364 control_message(pao, phm, phr);365 break;366 367 case HPI_OBJ_OSTREAM:368 outstream_message(pao, phm, phr);369 break;370 371 case HPI_OBJ_ISTREAM:372 instream_message(pao, phm, phr);373 break;374 375 default:376 hw_message(pao, phm, phr);377 break;378 }379 break;380 381 default:382 phr->error = HPI_ERROR_INVALID_TYPE;383 break;384 }385}386 387/************************************************************************/388/* SUBSYSTEM */389 390/* create an adapter object and initialise it based on resource information391 * passed in the message392 * NOTE - you cannot use this function AND the FindAdapters function at the393 * same time, the application must use only one of them to get the adapters394 */395static void subsys_create_adapter(struct hpi_message *phm,396 struct hpi_response *phr)397{398 /* create temp adapter obj, because we don't know what index yet */399 struct hpi_adapter_obj ao;400 struct hpi_adapter_obj *pao;401 u32 os_error_code;402 u16 err = 0;403 u32 dsp_index = 0;404 405 HPI_DEBUG_LOG(VERBOSE, "subsys_create_adapter\n");406 407 memset(&ao, 0, sizeof(ao));408 409 ao.priv = kzalloc(sizeof(struct hpi_hw_obj), GFP_KERNEL);410 if (!ao.priv) {411 HPI_DEBUG_LOG(ERROR, "can't get mem for adapter object\n");412 phr->error = HPI_ERROR_MEMORY_ALLOC;413 return;414 }415 416 /* create the adapter object based on the resource information */417 ao.pci = *phm->u.s.resource.r.pci;418 419 err = create_adapter_obj(&ao, &os_error_code);420 if (err) {421 delete_adapter_obj(&ao);422 if (err >= HPI_ERROR_BACKEND_BASE) {423 phr->error = HPI_ERROR_DSP_BOOTLOAD;424 phr->specific_error = err;425 } else {426 phr->error = err;427 }428 429 phr->u.s.data = os_error_code;430 return;431 }432 /* need to update paParentAdapter */433 pao = hpi_find_adapter(ao.index);434 if (!pao) {435 /* We just added this adapter, why can't we find it!? */436 HPI_DEBUG_LOG(ERROR, "lost adapter after boot\n");437 phr->error = HPI_ERROR_BAD_ADAPTER;438 return;439 }440 441 for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {442 struct hpi_hw_obj *phw = pao->priv;443 phw->ado[dsp_index].pa_parent_adapter = pao;444 }445 446 phr->u.s.adapter_type = ao.type;447 phr->u.s.adapter_index = ao.index;448 phr->error = 0;449}450 451static void adapter_delete(struct hpi_adapter_obj *pao,452 struct hpi_message *phm, struct hpi_response *phr)453{454 delete_adapter_obj(pao);455 hpi_delete_adapter(pao);456 phr->error = 0;457}458 459/* this routine is called from SubSysFindAdapter and SubSysCreateAdapter */460static short create_adapter_obj(struct hpi_adapter_obj *pao,461 u32 *pos_error_code)462{463 short boot_error = 0;464 u32 dsp_index = 0;465 u32 control_cache_size = 0;466 u32 control_cache_count = 0;467 struct hpi_hw_obj *phw = pao->priv;468 469 /* The PCI2040 has the following address map */470 /* BAR0 - 4K = HPI control and status registers on PCI2040 (HPI CSR) */471 /* BAR1 - 32K = HPI registers on DSP */472 phw->dw2040_HPICSR = pao->pci.ap_mem_base[0];473 phw->dw2040_HPIDSP = pao->pci.ap_mem_base[1];474 HPI_DEBUG_LOG(VERBOSE, "csr %p, dsp %p\n", phw->dw2040_HPICSR,475 phw->dw2040_HPIDSP);476 477 /* set addresses for the possible DSP HPI interfaces */478 for (dsp_index = 0; dsp_index < MAX_DSPS; dsp_index++) {479 phw->ado[dsp_index].prHPI_control =480 phw->dw2040_HPIDSP + (CONTROL +481 DSP_SPACING * dsp_index);482 483 phw->ado[dsp_index].prHPI_address =484 phw->dw2040_HPIDSP + (ADDRESS +485 DSP_SPACING * dsp_index);486 phw->ado[dsp_index].prHPI_data =487 phw->dw2040_HPIDSP + (DATA + DSP_SPACING * dsp_index);488 489 phw->ado[dsp_index].prHPI_data_auto_inc =490 phw->dw2040_HPIDSP + (DATA_AUTOINC +491 DSP_SPACING * dsp_index);492 493 HPI_DEBUG_LOG(VERBOSE, "ctl %p, adr %p, dat %p, dat++ %p\n",494 phw->ado[dsp_index].prHPI_control,495 phw->ado[dsp_index].prHPI_address,496 phw->ado[dsp_index].prHPI_data,497 phw->ado[dsp_index].prHPI_data_auto_inc);498 499 phw->ado[dsp_index].pa_parent_adapter = pao;500 }501 502 phw->pCI2040HPI_error_count = 0;503 pao->has_control_cache = 0;504 505 /* Set the default number of DSPs on this card */506 /* This is (conditionally) adjusted after bootloading */507 /* of the first DSP in the bootload section. */508 phw->num_dsp = 1;509 510 boot_error = hpi6000_adapter_boot_load_dsp(pao, pos_error_code);511 if (boot_error)512 return boot_error;513 514 HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");515 516 phw->message_buffer_address_on_dsp = 0L;517 phw->response_buffer_address_on_dsp = 0L;518 519 /* get info about the adapter by asking the adapter */520 /* send a HPI_ADAPTER_GET_INFO message */521 {522 struct hpi_message hm;523 struct hpi_response hr0; /* response from DSP 0 */524 struct hpi_response hr1; /* response from DSP 1 */525 u16 error = 0;526 527 HPI_DEBUG_LOG(VERBOSE, "send ADAPTER_GET_INFO\n");528 memset(&hm, 0, sizeof(hm));529 hm.type = HPI_TYPE_REQUEST;530 hm.size = sizeof(struct hpi_message);531 hm.object = HPI_OBJ_ADAPTER;532 hm.function = HPI_ADAPTER_GET_INFO;533 hm.adapter_index = 0;534 memset(&hr0, 0, sizeof(hr0));535 memset(&hr1, 0, sizeof(hr1));536 hr0.size = sizeof(hr0);537 hr1.size = sizeof(hr1);538 539 error = hpi6000_message_response_sequence(pao, 0, &hm, &hr0);540 if (hr0.error) {541 HPI_DEBUG_LOG(DEBUG, "message error %d\n", hr0.error);542 return hr0.error;543 }544 if (phw->num_dsp == 2) {545 error = hpi6000_message_response_sequence(pao, 1, &hm,546 &hr1);547 if (error)548 return error;549 }550 pao->type = hr0.u.ax.info.adapter_type;551 pao->index = hr0.u.ax.info.adapter_index;552 }553 554 memset(&phw->control_cache[0], 0,555 sizeof(struct hpi_control_cache_single) *556 HPI_NMIXER_CONTROLS);557 /* Read the control cache length to figure out if it is turned on */558 control_cache_size =559 hpi_read_word(&phw->ado[0],560 HPI_HIF_ADDR(control_cache_size_in_bytes));561 if (control_cache_size) {562 control_cache_count =563 hpi_read_word(&phw->ado[0],564 HPI_HIF_ADDR(control_cache_count));565 566 phw->p_cache =567 hpi_alloc_control_cache(control_cache_count,568 control_cache_size, (unsigned char *)569 &phw->control_cache[0]570 );571 if (phw->p_cache)572 pao->has_control_cache = 1;573 }574 575 HPI_DEBUG_LOG(DEBUG, "get adapter info ASI%04X index %d\n", pao->type,576 pao->index);577 578 if (phw->p_cache)579 phw->p_cache->adap_idx = pao->index;580 581 return hpi_add_adapter(pao);582}583 584static void delete_adapter_obj(struct hpi_adapter_obj *pao)585{586 struct hpi_hw_obj *phw = pao->priv;587 588 if (pao->has_control_cache)589 hpi_free_control_cache(phw->p_cache);590 591 /* reset DSPs on adapter */592 iowrite32(0x0003000F, phw->dw2040_HPICSR + HPI_RESET);593 594 kfree(phw);595}596 597/************************************************************************/598/* ADAPTER */599 600static void adapter_get_asserts(struct hpi_adapter_obj *pao,601 struct hpi_message *phm, struct hpi_response *phr)602{603#ifndef HIDE_PCI_ASSERTS604 /* if we have PCI2040 asserts then collect them */605 if ((gw_pci_read_asserts > 0) || (gw_pci_write_asserts > 0)) {606 phr->u.ax.assert.p1 =607 gw_pci_read_asserts * 100 + gw_pci_write_asserts;608 phr->u.ax.assert.p2 = 0;609 phr->u.ax.assert.count = 1; /* assert count */610 phr->u.ax.assert.dsp_index = -1; /* "dsp index" */611 strcpy(phr->u.ax.assert.sz_message, "PCI2040 error");612 phr->u.ax.assert.dsp_msg_addr = 0;613 gw_pci_read_asserts = 0;614 gw_pci_write_asserts = 0;615 phr->error = 0;616 } else617#endif618 hw_message(pao, phm, phr); /*get DSP asserts */619 620 return;621}622 623/************************************************************************/624/* LOW-LEVEL */625 626static short hpi6000_adapter_boot_load_dsp(struct hpi_adapter_obj *pao,627 u32 *pos_error_code)628{629 struct hpi_hw_obj *phw = pao->priv;630 short error;631 u32 timeout;632 u32 read = 0;633 u32 i = 0;634 u32 data = 0;635 u32 j = 0;636 u32 test_addr = 0x80000000;637 u32 test_data = 0x00000001;638 u32 dw2040_reset = 0;639 u32 dsp_index = 0;640 u32 endian = 0;641 u32 adapter_info = 0;642 u32 delay = 0;643 644 struct dsp_code dsp_code;645 u16 boot_load_family = 0;646 647 /* NOTE don't use wAdapterType in this routine. It is not setup yet */648 649 switch (pao->pci.pci_dev->subsystem_device) {650 case 0x5100:651 case 0x5110: /* ASI5100 revB or higher with C6711D */652 case 0x5200: /* ASI5200 PCIe version of ASI5100 */653 case 0x6100:654 case 0x6200:655 boot_load_family = HPI_ADAPTER_FAMILY_ASI(0x6200);656 break;657 default:658 return HPI6000_ERROR_UNHANDLED_SUBSYS_ID;659 }660 661 /* reset all DSPs, indicate two DSPs are present662 * set RST3-=1 to disconnect HAD8 to set DSP in little endian mode663 */664 endian = 0;665 dw2040_reset = 0x0003000F;666 iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);667 668 /* read back register to make sure PCI2040 chip is functioning669 * note that bits 4..15 are read-only and so should always return zero,670 * even though we wrote 1 to them671 */672 hpios_delay_micro_seconds(1000);673 delay = ioread32(phw->dw2040_HPICSR + HPI_RESET);674 675 if (delay != dw2040_reset) {676 HPI_DEBUG_LOG(ERROR, "INIT_PCI2040 %x %x\n", dw2040_reset,677 delay);678 return HPI6000_ERROR_INIT_PCI2040;679 }680 681 /* Indicate that DSP#0,1 is a C6X */682 iowrite32(0x00000003, phw->dw2040_HPICSR + HPI_DATA_WIDTH);683 /* set Bit30 and 29 - which will prevent Target aborts from being684 * issued upon HPI or GP error685 */686 iowrite32(0x60000000, phw->dw2040_HPICSR + INTERRUPT_MASK_SET);687 688 /* isolate DSP HAD8 line from PCI2040 so that689 * Little endian can be set by pullup690 */691 dw2040_reset = dw2040_reset & (~(endian << 3));692 iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);693 694 phw->ado[0].c_dsp_rev = 'B'; /* revB */695 phw->ado[1].c_dsp_rev = 'B'; /* revB */696 697 /*Take both DSPs out of reset, setting HAD8 to the correct Endian */698 dw2040_reset = dw2040_reset & (~0x00000001); /* start DSP 0 */699 iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);700 dw2040_reset = dw2040_reset & (~0x00000002); /* start DSP 1 */701 iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);702 703 /* set HAD8 back to PCI2040, now that DSP set to little endian mode */704 dw2040_reset = dw2040_reset & (~0x00000008);705 iowrite32(dw2040_reset, phw->dw2040_HPICSR + HPI_RESET);706 /*delay to allow DSP to get going */707 hpios_delay_micro_seconds(100);708 709 /* loop through all DSPs, downloading DSP code */710 for (dsp_index = 0; dsp_index < phw->num_dsp; dsp_index++) {711 struct dsp_obj *pdo = &phw->ado[dsp_index];712 713 /* configure DSP so that we download code into the SRAM */714 /* set control reg for little endian, HWOB=1 */715 iowrite32(0x00010001, pdo->prHPI_control);716 717 /* test access to the HPI address register (HPIA) */718 test_data = 0x00000001;719 for (j = 0; j < 32; j++) {720 iowrite32(test_data, pdo->prHPI_address);721 data = ioread32(pdo->prHPI_address);722 if (data != test_data) {723 HPI_DEBUG_LOG(ERROR, "INIT_DSPHPI %x %x %x\n",724 test_data, data, dsp_index);725 return HPI6000_ERROR_INIT_DSPHPI;726 }727 test_data = test_data << 1;728 }729 730/* if C6713 the setup PLL to generate 225MHz from 25MHz.731* Since the PLLDIV1 read is sometimes wrong, even on a C6713,732* we're going to do this unconditionally733*/734/* PLLDIV1 should have a value of 8000 after reset */735/*736 if (HpiReadWord(pdo,0x01B7C118) == 0x8000)737*/738 {739 /* C6713 datasheet says we cannot program PLL from HPI,740 * and indeed if we try to set the PLL multiply from the741 * HPI, the PLL does not seem to lock,742 * so we enable the PLL and use the default of x 7743 */744 /* bypass PLL */745 hpi_write_word(pdo, 0x01B7C100, 0x0000);746 hpios_delay_micro_seconds(100);747 748 /* ** use default of PLL x7 ** */749 /* EMIF = 225/3=75MHz */750 hpi_write_word(pdo, 0x01B7C120, 0x8002);751 hpios_delay_micro_seconds(100);752 753 /* peri = 225/2 */754 hpi_write_word(pdo, 0x01B7C11C, 0x8001);755 hpios_delay_micro_seconds(100);756 757 /* cpu = 225/1 */758 hpi_write_word(pdo, 0x01B7C118, 0x8000);759 760 /* ~2ms delay */761 hpios_delay_micro_seconds(2000);762 763 /* PLL not bypassed */764 hpi_write_word(pdo, 0x01B7C100, 0x0001);765 /* ~2ms delay */766 hpios_delay_micro_seconds(2000);767 }768 769 /* test r/w to internal DSP memory770 * C6711 has L2 cache mapped to 0x0 when reset771 *772 * revB - because of bug 3.0.1 last HPI read773 * (before HPI address issued) must be non-autoinc774 */775 /* test each bit in the 32bit word */776 for (i = 0; i < 100; i++) {777 test_addr = 0x00000000;778 test_data = 0x00000001;779 for (j = 0; j < 32; j++) {780 hpi_write_word(pdo, test_addr + i, test_data);781 data = hpi_read_word(pdo, test_addr + i);782 if (data != test_data) {783 HPI_DEBUG_LOG(ERROR,784 "DSP mem %x %x %x %x\n",785 test_addr + i, test_data,786 data, dsp_index);787 788 return HPI6000_ERROR_INIT_DSPINTMEM;789 }790 test_data = test_data << 1;791 }792 }793 794 /* memory map of ASI6200795 00000000-0000FFFF 16Kx32 internal program796 01800000-019FFFFF Internal peripheral797 80000000-807FFFFF CE0 2Mx32 SDRAM running @ 100MHz798 90000000-9000FFFF CE1 Async peripherals:799 800 EMIF config801 ------------802 Global EMIF control803 0 -804 1 -805 2 -806 3 CLK2EN = 1 CLKOUT2 enabled807 4 CLK1EN = 0 CLKOUT1 disabled808 5 EKEN = 1 <--!! C6713 specific, enables ECLKOUT809 6 -810 7 NOHOLD = 1 external HOLD disabled811 8 HOLDA = 0 HOLDA output is low812 9 HOLD = 0 HOLD input is low813 10 ARDY = 1 ARDY input is high814 11 BUSREQ = 0 BUSREQ output is low815 12,13 Reserved = 1816 */817 hpi_write_word(pdo, 0x01800000, 0x34A8);818 819 /* EMIF CE0 setup - 2Mx32 Sync DRAM820 31..28 Wr setup821 27..22 Wr strobe822 21..20 Wr hold823 19..16 Rd setup824 15..14 -825 13..8 Rd strobe826 7..4 MTYPE 0011 Sync DRAM 32bits827 3 Wr hold MSB828 2..0 Rd hold829 */830 hpi_write_word(pdo, 0x01800008, 0x00000030);831 832 /* EMIF SDRAM Extension833 31-21 0834 20 WR2RD = 0835 19-18 WR2DEAC = 1836 17 WR2WR = 0837 16-15 R2WDQM = 2838 14-12 RD2WR = 4839 11-10 RD2DEAC = 1840 9 RD2RD = 1841 8-7 THZP = 10b842 6-5 TWR = 2-1 = 01b (tWR = 10ns)843 4 TRRD = 0b = 2 ECLK (tRRD = 14ns)844 3-1 TRAS = 5-1 = 100b (Tras=42ns = 5 ECLK)845 1 CAS latency = 3 ECLK846 (for Micron 2M32-7 operating at 100Mhz)847 */848 849 /* need to use this else DSP code crashes */850 hpi_write_word(pdo, 0x01800020, 0x001BDF29);851 852 /* EMIF SDRAM control - set up for a 2Mx32 SDRAM (512x32x4 bank)853 31 - -854 30 SDBSZ 1 4 bank855 29..28 SDRSZ 00 11 row address pins856 27..26 SDCSZ 01 8 column address pins857 25 RFEN 1 refersh enabled858 24 INIT 1 init SDRAM859 23..20 TRCD 0001860 19..16 TRP 0001861 15..12 TRC 0110862 11..0 - -863 */864 /* need to use this else DSP code crashes */865 hpi_write_word(pdo, 0x01800018, 0x47117000);866 867 /* EMIF SDRAM Refresh Timing */868 hpi_write_word(pdo, 0x0180001C, 0x00000410);869 870 /*MIF CE1 setup - Async peripherals871 @100MHz bus speed, each cycle is 10ns,872 31..28 Wr setup = 1873 27..22 Wr strobe = 3 30ns874 21..20 Wr hold = 1875 19..16 Rd setup =1876 15..14 Ta = 2877 13..8 Rd strobe = 3 30ns878 7..4 MTYPE 0010 Async 32bits879 3 Wr hold MSB =0880 2..0 Rd hold = 1881 */882 {883 u32 cE1 =884 (1L << 28) | (3L << 22) | (1L << 20) | (1L <<885 16) | (2L << 14) | (3L << 8) | (2L << 4) | 1L;886 hpi_write_word(pdo, 0x01800004, cE1);887 }888 889 /* delay a little to allow SDRAM and DSP to "get going" */890 hpios_delay_micro_seconds(1000);891 892 /* test access to SDRAM */893 {894 test_addr = 0x80000000;895 test_data = 0x00000001;896 /* test each bit in the 32bit word */897 for (j = 0; j < 32; j++) {898 hpi_write_word(pdo, test_addr, test_data);899 data = hpi_read_word(pdo, test_addr);900 if (data != test_data) {901 HPI_DEBUG_LOG(ERROR,902 "DSP dram %x %x %x %x\n",903 test_addr, test_data, data,904 dsp_index);905 906 return HPI6000_ERROR_INIT_SDRAM1;907 }908 test_data = test_data << 1;909 }910 /* test every Nth address in the DRAM */911#define DRAM_SIZE_WORDS 0x200000 /*2_mx32 */912#define DRAM_INC 1024913 test_addr = 0x80000000;914 test_data = 0x0;915 for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) {916 hpi_write_word(pdo, test_addr + i, test_data);917 test_data++;918 }919 test_addr = 0x80000000;920 test_data = 0x0;921 for (i = 0; i < DRAM_SIZE_WORDS; i = i + DRAM_INC) {922 data = hpi_read_word(pdo, test_addr + i);923 if (data != test_data) {924 HPI_DEBUG_LOG(ERROR,925 "DSP dram %x %x %x %x\n",926 test_addr + i, test_data,927 data, dsp_index);928 return HPI6000_ERROR_INIT_SDRAM2;929 }930 test_data++;931 }932 933 }934 935 /* write the DSP code down into the DSPs memory */936 error = hpi_dsp_code_open(boot_load_family, pao->pci.pci_dev,937 &dsp_code, pos_error_code);938 939 if (error)940 return error;941 942 while (1) {943 u32 length;944 u32 address;945 u32 type;946 u32 *pcode;947 948 error = hpi_dsp_code_read_word(&dsp_code, &length);949 if (error)950 break;951 if (length == 0xFFFFFFFF)952 break; /* end of code */953 954 error = hpi_dsp_code_read_word(&dsp_code, &address);955 if (error)956 break;957 error = hpi_dsp_code_read_word(&dsp_code, &type);958 if (error)959 break;960 error = hpi_dsp_code_read_block(length, &dsp_code,961 &pcode);962 if (error)963 break;964 error = hpi6000_dsp_block_write32(pao, (u16)dsp_index,965 address, pcode, length);966 if (error)967 break;968 }969 970 if (error) {971 hpi_dsp_code_close(&dsp_code);972 return error;973 }974 /* verify that code was written correctly */975 /* this time through, assume no errors in DSP code file/array */976 hpi_dsp_code_rewind(&dsp_code);977 while (1) {978 u32 length;979 u32 address;980 u32 type;981 u32 *pcode;982 983 hpi_dsp_code_read_word(&dsp_code, &length);984 if (length == 0xFFFFFFFF)985 break; /* end of code */986 987 hpi_dsp_code_read_word(&dsp_code, &address);988 hpi_dsp_code_read_word(&dsp_code, &type);989 hpi_dsp_code_read_block(length, &dsp_code, &pcode);990 991 for (i = 0; i < length; i++) {992 data = hpi_read_word(pdo, address);993 if (data != *pcode) {994 error = HPI6000_ERROR_INIT_VERIFY;995 HPI_DEBUG_LOG(ERROR,996 "DSP verify %x %x %x %x\n",997 address, *pcode, data,998 dsp_index);999 break;1000 }1001 pcode++;1002 address += 4;1003 }1004 if (error)1005 break;1006 }1007 hpi_dsp_code_close(&dsp_code);1008 if (error)1009 return error;1010 1011 /* zero out the hostmailbox */1012 {1013 u32 address = HPI_HIF_ADDR(host_cmd);1014 for (i = 0; i < 4; i++) {1015 hpi_write_word(pdo, address, 0);1016 address += 4;1017 }1018 }1019 /* write the DSP number into the hostmailbox */1020 /* structure before starting the DSP */1021 hpi_write_word(pdo, HPI_HIF_ADDR(dsp_number), dsp_index);1022 1023 /* write the DSP adapter Info into the */1024 /* hostmailbox before starting the DSP */1025 if (dsp_index > 0)1026 hpi_write_word(pdo, HPI_HIF_ADDR(adapter_info),1027 adapter_info);1028 1029 /* step 3. Start code by sending interrupt */1030 iowrite32(0x00030003, pdo->prHPI_control);1031 hpios_delay_micro_seconds(10000);1032 1033 /* wait for a non-zero value in hostcmd -1034 * indicating initialization is complete1035 *1036 * Init could take a while if DSP checks SDRAM memory1037 * Was 200000. Increased to 2000000 for ASI8801 so we1038 * don't get 938 errors.1039 */1040 timeout = 2000000;1041 while (timeout) {1042 do {1043 read = hpi_read_word(pdo,1044 HPI_HIF_ADDR(host_cmd));1045 } while (--timeout1046 && hpi6000_check_PCI2040_error_flag(pao,1047 H6READ));1048 1049 if (read)1050 break;1051 /* The following is a workaround for bug #94:1052 * Bluescreen on install and subsequent boots on a1053 * DELL PowerEdge 600SC PC with 1.8GHz P4 and1054 * ServerWorks chipset. Without this delay the system1055 * locks up with a bluescreen (NOT GPF or pagefault).1056 */1057 else1058 hpios_delay_micro_seconds(10000);1059 }1060 if (timeout == 0)1061 return HPI6000_ERROR_INIT_NOACK;1062 1063 /* read the DSP adapter Info from the */1064 /* hostmailbox structure after starting the DSP */1065 if (dsp_index == 0) {1066 /*u32 dwTestData=0; */1067 u32 mask = 0;1068 1069 adapter_info =1070 hpi_read_word(pdo,1071 HPI_HIF_ADDR(adapter_info));1072 if (HPI_ADAPTER_FAMILY_ASI1073 (HPI_HIF_ADAPTER_INFO_EXTRACT_ADAPTER1074 (adapter_info)) ==1075 HPI_ADAPTER_FAMILY_ASI(0x6200))1076 /* all 6200 cards have this many DSPs */1077 phw->num_dsp = 2;1078 1079 /* test that the PLD is programmed */1080 /* and we can read/write 24bits */1081#define PLD_BASE_ADDRESS 0x90000000L /*for ASI6100/6200/8800 */1082 1083 switch (boot_load_family) {1084 case HPI_ADAPTER_FAMILY_ASI(0x6200):1085 /* ASI6100/6200 has 24bit path to FPGA */1086 mask = 0xFFFFFF00L;1087 /* ASI5100 uses AX6 code, */1088 /* but has no PLD r/w register to test */1089 if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev->1090 subsystem_device) ==1091 HPI_ADAPTER_FAMILY_ASI(0x5100))1092 mask = 0x00000000L;1093 /* ASI5200 uses AX6 code, */1094 /* but has no PLD r/w register to test */1095 if (HPI_ADAPTER_FAMILY_ASI(pao->pci.pci_dev->1096 subsystem_device) ==1097 HPI_ADAPTER_FAMILY_ASI(0x5200))1098 mask = 0x00000000L;1099 break;1100 case HPI_ADAPTER_FAMILY_ASI(0x8800):1101 /* ASI8800 has 16bit path to FPGA */1102 mask = 0xFFFF0000L;1103 break;1104 }1105 test_data = 0xAAAAAA00L & mask;1106 /* write to 24 bit Debug register (D31-D8) */1107 hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data);1108 read = hpi_read_word(pdo,1109 PLD_BASE_ADDRESS + 4L) & mask;1110 if (read != test_data) {1111 HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data,1112 read);1113 return HPI6000_ERROR_INIT_PLDTEST1;1114 }1115 test_data = 0x55555500L & mask;1116 hpi_write_word(pdo, PLD_BASE_ADDRESS + 4L, test_data);1117 read = hpi_read_word(pdo,1118 PLD_BASE_ADDRESS + 4L) & mask;1119 if (read != test_data) {1120 HPI_DEBUG_LOG(ERROR, "PLD %x %x\n", test_data,1121 read);1122 return HPI6000_ERROR_INIT_PLDTEST2;1123 }1124 }1125 } /* for numDSP */1126 return 0;1127}1128 1129#define PCI_TIMEOUT 1001130 1131static int hpi_set_address(struct dsp_obj *pdo, u32 address)1132{1133 u32 timeout = PCI_TIMEOUT;1134 1135 do {1136 iowrite32(address, pdo->prHPI_address);1137 } while (hpi6000_check_PCI2040_error_flag(pdo->pa_parent_adapter,1138 H6WRITE)1139 && --timeout);1140 1141 if (timeout)1142 return 0;1143 1144 return 1;1145}1146 1147/* write one word to the HPI port */1148static void hpi_write_word(struct dsp_obj *pdo, u32 address, u32 data)1149{1150 if (hpi_set_address(pdo, address))1151 return;1152 iowrite32(data, pdo->prHPI_data);1153}1154 1155/* read one word from the HPI port */1156static u32 hpi_read_word(struct dsp_obj *pdo, u32 address)1157{1158 u32 data = 0;1159 1160 if (hpi_set_address(pdo, address))1161 return 0; /*? No way to return error */1162 1163 /* take care of errata in revB DSP (2.0.1) */1164 data = ioread32(pdo->prHPI_data);1165 return data;1166}1167 1168/* write a block of 32bit words to the DSP HPI port using auto-inc mode */1169static void hpi_write_block(struct dsp_obj *pdo, u32 address, u32 *pdata,1170 u32 length)1171{1172 u16 length16 = length - 1;1173 1174 if (length == 0)1175 return;1176 1177 if (hpi_set_address(pdo, address))1178 return;1179 1180 iowrite32_rep(pdo->prHPI_data_auto_inc, pdata, length16);1181 1182 /* take care of errata in revB DSP (2.0.1) */1183 /* must end with non auto-inc */1184 iowrite32(*(pdata + length - 1), pdo->prHPI_data);1185}1186 1187/** read a block of 32bit words from the DSP HPI port using auto-inc mode1188 */1189static void hpi_read_block(struct dsp_obj *pdo, u32 address, u32 *pdata,1190 u32 length)1191{1192 u16 length16 = length - 1;1193 1194 if (length == 0)1195 return;1196 1197 if (hpi_set_address(pdo, address))1198 return;1199 1200 ioread32_rep(pdo->prHPI_data_auto_inc, pdata, length16);1201 1202 /* take care of errata in revB DSP (2.0.1) */1203 /* must end with non auto-inc */1204 *(pdata + length - 1) = ioread32(pdo->prHPI_data);1205}1206 1207static u16 hpi6000_dsp_block_write32(struct hpi_adapter_obj *pao,1208 u16 dsp_index, u32 hpi_address, u32 *source, u32 count)1209{1210 struct hpi_hw_obj *phw = pao->priv;1211 struct dsp_obj *pdo = &phw->ado[dsp_index];1212 u32 time_out = PCI_TIMEOUT;1213 int c6711_burst_size = 128;1214 u32 local_hpi_address = hpi_address;1215 int local_count = count;1216 int xfer_size;1217 u32 *pdata = source;1218 1219 while (local_count) {1220 if (local_count > c6711_burst_size)1221 xfer_size = c6711_burst_size;1222 else1223 xfer_size = local_count;1224 1225 time_out = PCI_TIMEOUT;1226 do {1227 hpi_write_block(pdo, local_hpi_address, pdata,1228 xfer_size);1229 } while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE)1230 && --time_out);1231 1232 if (!time_out)1233 break;1234 pdata += xfer_size;1235 local_hpi_address += sizeof(u32) * xfer_size;1236 local_count -= xfer_size;1237 }1238 1239 if (time_out)1240 return 0;1241 else1242 return 1;1243}1244 1245static u16 hpi6000_dsp_block_read32(struct hpi_adapter_obj *pao,1246 u16 dsp_index, u32 hpi_address, u32 *dest, u32 count)1247{1248 struct hpi_hw_obj *phw = pao->priv;1249 struct dsp_obj *pdo = &phw->ado[dsp_index];1250 u32 time_out = PCI_TIMEOUT;1251 int c6711_burst_size = 16;1252 u32 local_hpi_address = hpi_address;1253 int local_count = count;1254 int xfer_size;1255 u32 *pdata = dest;1256 1257 while (local_count) {1258 if (local_count > c6711_burst_size)1259 xfer_size = c6711_burst_size;1260 else1261 xfer_size = local_count;1262 1263 time_out = PCI_TIMEOUT;1264 do {1265 hpi_read_block(pdo, local_hpi_address, pdata,1266 xfer_size);1267 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ)1268 && --time_out);1269 if (!time_out)1270 break;1271 1272 pdata += xfer_size;1273 local_hpi_address += sizeof(u32) * xfer_size;1274 local_count -= xfer_size;1275 }1276 1277 if (time_out)1278 return 0;1279 else1280 return 1;1281}1282 1283static short hpi6000_message_response_sequence(struct hpi_adapter_obj *pao,1284 u16 dsp_index, struct hpi_message *phm, struct hpi_response *phr)1285{1286 struct hpi_hw_obj *phw = pao->priv;1287 struct dsp_obj *pdo = &phw->ado[dsp_index];1288 u32 timeout;1289 u16 ack;1290 u32 address;1291 u32 length;1292 u32 *p_data;1293 u16 error = 0;1294 1295 ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);1296 if (ack & HPI_HIF_ERROR_MASK) {1297 pao->dsp_crashed++;1298 return HPI6000_ERROR_MSG_RESP_IDLE_TIMEOUT;1299 }1300 pao->dsp_crashed = 0;1301 1302 /* get the message address and size */1303 if (phw->message_buffer_address_on_dsp == 0) {1304 timeout = TIMEOUT;1305 do {1306 address =1307 hpi_read_word(pdo,1308 HPI_HIF_ADDR(message_buffer_address));1309 phw->message_buffer_address_on_dsp = address;1310 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ)1311 && --timeout);1312 if (!timeout)1313 return HPI6000_ERROR_MSG_GET_ADR;1314 } else1315 address = phw->message_buffer_address_on_dsp;1316 1317 length = phm->size;1318 1319 /* send the message */1320 p_data = (u32 *)phm;1321 if (hpi6000_dsp_block_write32(pao, dsp_index, address, p_data,1322 (u16)length / 4))1323 return HPI6000_ERROR_MSG_RESP_BLOCKWRITE32;1324 1325 if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_GET_RESP))1326 return HPI6000_ERROR_MSG_RESP_GETRESPCMD;1327 hpi6000_send_dsp_interrupt(pdo);1328 1329 ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_RESP);1330 if (ack & HPI_HIF_ERROR_MASK)1331 return HPI6000_ERROR_MSG_RESP_GET_RESP_ACK;1332 1333 /* get the response address */1334 if (phw->response_buffer_address_on_dsp == 0) {1335 timeout = TIMEOUT;1336 do {1337 address =1338 hpi_read_word(pdo,1339 HPI_HIF_ADDR(response_buffer_address));1340 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ)1341 && --timeout);1342 phw->response_buffer_address_on_dsp = address;1343 1344 if (!timeout)1345 return HPI6000_ERROR_RESP_GET_ADR;1346 } else1347 address = phw->response_buffer_address_on_dsp;1348 1349 /* read the length of the response back from the DSP */1350 timeout = TIMEOUT;1351 do {1352 length = hpi_read_word(pdo, HPI_HIF_ADDR(length));1353 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);1354 if (!timeout)1355 return HPI6000_ERROR_RESP_GET_LEN;1356 1357 if (length > phr->size)1358 return HPI_ERROR_RESPONSE_BUFFER_TOO_SMALL;1359 1360 /* get the response */1361 p_data = (u32 *)phr;1362 if (hpi6000_dsp_block_read32(pao, dsp_index, address, p_data,1363 (u16)length / 4))1364 return HPI6000_ERROR_MSG_RESP_BLOCKREAD32;1365 1366 /* set i/f back to idle */1367 if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))1368 return HPI6000_ERROR_MSG_RESP_IDLECMD;1369 hpi6000_send_dsp_interrupt(pdo);1370 1371 error = hpi_validate_response(phm, phr);1372 return error;1373}1374 1375/* have to set up the below defines to match stuff in the MAP file */1376 1377#define MSG_ADDRESS (HPI_HIF_BASE+0x18)1378#define MSG_LENGTH 111379#define RESP_ADDRESS (HPI_HIF_BASE+0x44)1380#define RESP_LENGTH 161381#define QUEUE_START (HPI_HIF_BASE+0x88)1382#define QUEUE_SIZE 0x80001383 1384static short hpi6000_send_data_check_adr(u32 address, u32 length_in_dwords)1385{1386/*#define CHECKING // comment this line in to enable checking */1387#ifdef CHECKING1388 if (address < (u32)MSG_ADDRESS)1389 return 0;1390 if (address > (u32)(QUEUE_START + QUEUE_SIZE))1391 return 0;1392 if ((address + (length_in_dwords << 2)) >1393 (u32)(QUEUE_START + QUEUE_SIZE))1394 return 0;1395#else1396 (void)address;1397 (void)length_in_dwords;1398 return 1;1399#endif1400}1401 1402static short hpi6000_send_data(struct hpi_adapter_obj *pao, u16 dsp_index,1403 struct hpi_message *phm, struct hpi_response *phr)1404{1405 struct hpi_hw_obj *phw = pao->priv;1406 struct dsp_obj *pdo = &phw->ado[dsp_index];1407 u32 data_sent = 0;1408 u16 ack;1409 u32 length, address;1410 u32 *p_data = (u32 *)phm->u.d.u.data.pb_data;1411 u16 time_out = 8;1412 1413 (void)phr;1414 1415 /* round dwDataSize down to nearest 4 bytes */1416 while ((data_sent < (phm->u.d.u.data.data_size & ~3L))1417 && --time_out) {1418 ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);1419 if (ack & HPI_HIF_ERROR_MASK)1420 return HPI6000_ERROR_SEND_DATA_IDLE_TIMEOUT;1421 1422 if (hpi6000_send_host_command(pao, dsp_index,1423 HPI_HIF_SEND_DATA))1424 return HPI6000_ERROR_SEND_DATA_CMD;1425 1426 hpi6000_send_dsp_interrupt(pdo);1427 1428 ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_SEND_DATA);1429 1430 if (ack & HPI_HIF_ERROR_MASK)1431 return HPI6000_ERROR_SEND_DATA_ACK;1432 1433 do {1434 /* get the address and size */1435 address = hpi_read_word(pdo, HPI_HIF_ADDR(address));1436 /* DSP returns number of DWORDS */1437 length = hpi_read_word(pdo, HPI_HIF_ADDR(length));1438 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ));1439 1440 if (!hpi6000_send_data_check_adr(address, length))1441 return HPI6000_ERROR_SEND_DATA_ADR;1442 1443 /* send the data. break data into 512 DWORD blocks (2K bytes)1444 * and send using block write. 2Kbytes is the max as this is the1445 * memory window given to the HPI data register by the PCI20401446 */1447 1448 {1449 u32 len = length;1450 u32 blk_len = 512;1451 while (len) {1452 if (len < blk_len)1453 blk_len = len;1454 if (hpi6000_dsp_block_write32(pao, dsp_index,1455 address, p_data, blk_len))1456 return HPI6000_ERROR_SEND_DATA_WRITE;1457 address += blk_len * 4;1458 p_data += blk_len;1459 len -= blk_len;1460 }1461 }1462 1463 if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))1464 return HPI6000_ERROR_SEND_DATA_IDLECMD;1465 1466 hpi6000_send_dsp_interrupt(pdo);1467 1468 data_sent += length * 4;1469 }1470 if (!time_out)1471 return HPI6000_ERROR_SEND_DATA_TIMEOUT;1472 return 0;1473}1474 1475static short hpi6000_get_data(struct hpi_adapter_obj *pao, u16 dsp_index,1476 struct hpi_message *phm, struct hpi_response *phr)1477{1478 struct hpi_hw_obj *phw = pao->priv;1479 struct dsp_obj *pdo = &phw->ado[dsp_index];1480 u32 data_got = 0;1481 u16 ack;1482 u32 length, address;1483 u32 *p_data = (u32 *)phm->u.d.u.data.pb_data;1484 1485 (void)phr; /* this parameter not used! */1486 1487 /* round dwDataSize down to nearest 4 bytes */1488 while (data_got < (phm->u.d.u.data.data_size & ~3L)) {1489 ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_IDLE);1490 if (ack & HPI_HIF_ERROR_MASK)1491 return HPI6000_ERROR_GET_DATA_IDLE_TIMEOUT;1492 1493 if (hpi6000_send_host_command(pao, dsp_index,1494 HPI_HIF_GET_DATA))1495 return HPI6000_ERROR_GET_DATA_CMD;1496 hpi6000_send_dsp_interrupt(pdo);1497 1498 ack = hpi6000_wait_dsp_ack(pao, dsp_index, HPI_HIF_GET_DATA);1499 1500 if (ack & HPI_HIF_ERROR_MASK)1501 return HPI6000_ERROR_GET_DATA_ACK;1502 1503 /* get the address and size */1504 do {1505 address = hpi_read_word(pdo, HPI_HIF_ADDR(address));1506 length = hpi_read_word(pdo, HPI_HIF_ADDR(length));1507 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ));1508 1509 /* read the data */1510 {1511 u32 len = length;1512 u32 blk_len = 512;1513 while (len) {1514 if (len < blk_len)1515 blk_len = len;1516 if (hpi6000_dsp_block_read32(pao, dsp_index,1517 address, p_data, blk_len))1518 return HPI6000_ERROR_GET_DATA_READ;1519 address += blk_len * 4;1520 p_data += blk_len;1521 len -= blk_len;1522 }1523 }1524 1525 if (hpi6000_send_host_command(pao, dsp_index, HPI_HIF_IDLE))1526 return HPI6000_ERROR_GET_DATA_IDLECMD;1527 hpi6000_send_dsp_interrupt(pdo);1528 1529 data_got += length * 4;1530 }1531 return 0;1532}1533 1534static void hpi6000_send_dsp_interrupt(struct dsp_obj *pdo)1535{1536 iowrite32(0x00030003, pdo->prHPI_control); /* DSPINT */1537}1538 1539static short hpi6000_send_host_command(struct hpi_adapter_obj *pao,1540 u16 dsp_index, u32 host_cmd)1541{1542 struct hpi_hw_obj *phw = pao->priv;1543 struct dsp_obj *pdo = &phw->ado[dsp_index];1544 u32 timeout = TIMEOUT;1545 1546 /* set command */1547 do {1548 hpi_write_word(pdo, HPI_HIF_ADDR(host_cmd), host_cmd);1549 /* flush the FIFO */1550 hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd));1551 } while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE) && --timeout);1552 1553 /* reset the interrupt bit */1554 iowrite32(0x00040004, pdo->prHPI_control);1555 1556 if (timeout)1557 return 0;1558 else1559 return 1;1560}1561 1562/* if the PCI2040 has recorded an HPI timeout, reset the error and return 1 */1563static short hpi6000_check_PCI2040_error_flag(struct hpi_adapter_obj *pao,1564 u16 read_or_write)1565{1566 u32 hPI_error;1567 1568 struct hpi_hw_obj *phw = pao->priv;1569 1570 /* read the error bits from the PCI2040 */1571 hPI_error = ioread32(phw->dw2040_HPICSR + HPI_ERROR_REPORT);1572 if (hPI_error) {1573 /* reset the error flag */1574 iowrite32(0L, phw->dw2040_HPICSR + HPI_ERROR_REPORT);1575 phw->pCI2040HPI_error_count++;1576 if (read_or_write == 1)1577 gw_pci_read_asserts++; /************* inc global */1578 else1579 gw_pci_write_asserts++;1580 return 1;1581 } else1582 return 0;1583}1584 1585static short hpi6000_wait_dsp_ack(struct hpi_adapter_obj *pao, u16 dsp_index,1586 u32 ack_value)1587{1588 struct hpi_hw_obj *phw = pao->priv;1589 struct dsp_obj *pdo = &phw->ado[dsp_index];1590 u32 ack = 0L;1591 u32 timeout;1592 u32 hPIC = 0L;1593 1594 /* wait for host interrupt to signal ack is ready */1595 timeout = TIMEOUT;1596 while (--timeout) {1597 hPIC = ioread32(pdo->prHPI_control);1598 if (hPIC & 0x04) /* 0x04 = HINT from DSP */1599 break;1600 }1601 if (timeout == 0)1602 return HPI_HIF_ERROR_MASK;1603 1604 /* wait for dwAckValue */1605 timeout = TIMEOUT;1606 while (--timeout) {1607 /* read the ack mailbox */1608 ack = hpi_read_word(pdo, HPI_HIF_ADDR(dsp_ack));1609 if (ack == ack_value)1610 break;1611 if ((ack & HPI_HIF_ERROR_MASK)1612 && !hpi6000_check_PCI2040_error_flag(pao, H6READ))1613 break;1614 /*for (i=0;i<1000;i++) */1615 /* dwPause=i+1; */1616 }1617 if (ack & HPI_HIF_ERROR_MASK)1618 /* indicates bad read from DSP -1619 typically 0xffffff is read for some reason */1620 ack = HPI_HIF_ERROR_MASK;1621 1622 if (timeout == 0)1623 ack = HPI_HIF_ERROR_MASK;1624 return (short)ack;1625}1626 1627static short hpi6000_update_control_cache(struct hpi_adapter_obj *pao,1628 struct hpi_message *phm)1629{1630 const u16 dsp_index = 0;1631 struct hpi_hw_obj *phw = pao->priv;1632 struct dsp_obj *pdo = &phw->ado[dsp_index];1633 u32 timeout;1634 u32 cache_dirty_flag;1635 u16 err;1636 1637 hpios_dsplock_lock(pao);1638 1639 timeout = TIMEOUT;1640 do {1641 cache_dirty_flag =1642 hpi_read_word((struct dsp_obj *)pdo,1643 HPI_HIF_ADDR(control_cache_is_dirty));1644 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ) && --timeout);1645 if (!timeout) {1646 err = HPI6000_ERROR_CONTROL_CACHE_PARAMS;1647 goto unlock;1648 }1649 1650 if (cache_dirty_flag) {1651 /* read the cached controls */1652 u32 address;1653 u32 length;1654 1655 timeout = TIMEOUT;1656 if (pdo->control_cache_address_on_dsp == 0) {1657 do {1658 address =1659 hpi_read_word((struct dsp_obj *)pdo,1660 HPI_HIF_ADDR(control_cache_address));1661 1662 length = hpi_read_word((struct dsp_obj *)pdo,1663 HPI_HIF_ADDR1664 (control_cache_size_in_bytes));1665 } while (hpi6000_check_PCI2040_error_flag(pao, H6READ)1666 && --timeout);1667 if (!timeout) {1668 err = HPI6000_ERROR_CONTROL_CACHE_ADDRLEN;1669 goto unlock;1670 }1671 pdo->control_cache_address_on_dsp = address;1672 pdo->control_cache_length_on_dsp = length;1673 } else {1674 address = pdo->control_cache_address_on_dsp;1675 length = pdo->control_cache_length_on_dsp;1676 }1677 1678 if (hpi6000_dsp_block_read32(pao, dsp_index, address,1679 (u32 *)&phw->control_cache[0],1680 length / sizeof(u32))) {1681 err = HPI6000_ERROR_CONTROL_CACHE_READ;1682 goto unlock;1683 }1684 do {1685 hpi_write_word((struct dsp_obj *)pdo,1686 HPI_HIF_ADDR(control_cache_is_dirty), 0);1687 /* flush the FIFO */1688 hpi_set_address(pdo, HPI_HIF_ADDR(host_cmd));1689 } while (hpi6000_check_PCI2040_error_flag(pao, H6WRITE)1690 && --timeout);1691 if (!timeout) {1692 err = HPI6000_ERROR_CONTROL_CACHE_FLUSH;1693 goto unlock;1694 }1695 1696 }1697 err = 0;1698 1699unlock:1700 hpios_dsplock_unlock(pao);1701 return err;1702}1703 1704/** Get dsp index for multi DSP adapters only */1705static u16 get_dsp_index(struct hpi_adapter_obj *pao, struct hpi_message *phm)1706{1707 u16 ret = 0;1708 switch (phm->object) {1709 case HPI_OBJ_ISTREAM:1710 if (phm->obj_index < 2)1711 ret = 1;1712 break;1713 case HPI_OBJ_PROFILE:1714 ret = phm->obj_index;1715 break;1716 default:1717 break;1718 }1719 return ret;1720}1721 1722/** Complete transaction with DSP1723 1724Send message, get response, send or get stream data if any.1725*/1726static void hw_message(struct hpi_adapter_obj *pao, struct hpi_message *phm,1727 struct hpi_response *phr)1728{1729 u16 error = 0;1730 u16 dsp_index = 0;1731 struct hpi_hw_obj *phw = pao->priv;1732 u16 num_dsp = phw->num_dsp;1733 1734 if (num_dsp < 2)1735 dsp_index = 0;1736 else {1737 dsp_index = get_dsp_index(pao, phm);1738 1739 /* is this checked on the DSP anyway? */1740 if ((phm->function == HPI_ISTREAM_GROUP_ADD)1741 || (phm->function == HPI_OSTREAM_GROUP_ADD)) {1742 struct hpi_message hm;1743 u16 add_index;1744 hm.obj_index = phm->u.d.u.stream.stream_index;1745 hm.object = phm->u.d.u.stream.object_type;1746 add_index = get_dsp_index(pao, &hm);1747 if (add_index != dsp_index) {1748 phr->error = HPI_ERROR_NO_INTERDSP_GROUPS;1749 return;1750 }1751 }1752 }1753 1754 hpios_dsplock_lock(pao);1755 error = hpi6000_message_response_sequence(pao, dsp_index, phm, phr);1756 1757 if (error) /* something failed in the HPI/DSP interface */1758 goto err;1759 1760 if (phr->error) /* something failed in the DSP */1761 goto out;1762 1763 switch (phm->function) {1764 case HPI_OSTREAM_WRITE:1765 case HPI_ISTREAM_ANC_WRITE:1766 error = hpi6000_send_data(pao, dsp_index, phm, phr);1767 break;1768 case HPI_ISTREAM_READ:1769 case HPI_OSTREAM_ANC_READ:1770 error = hpi6000_get_data(pao, dsp_index, phm, phr);1771 break;1772 case HPI_ADAPTER_GET_ASSERT:1773 phr->u.ax.assert.dsp_index = 0; /* dsp 0 default */1774 if (num_dsp == 2) {1775 if (!phr->u.ax.assert.count) {1776 /* no assert from dsp 0, check dsp 1 */1777 error = hpi6000_message_response_sequence(pao,1778 1, phm, phr);1779 phr->u.ax.assert.dsp_index = 1;1780 }1781 }1782 }1783 1784err:1785 if (error) {1786 if (error >= HPI_ERROR_BACKEND_BASE) {1787 phr->error = HPI_ERROR_DSP_COMMUNICATION;1788 phr->specific_error = error;1789 } else {1790 phr->error = error;1791 }1792 1793 /* just the header of the response is valid */1794 phr->size = sizeof(struct hpi_response_header);1795 }1796out:1797 hpios_dsplock_unlock(pao);1798 return;1799}1800