#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/sunddi.h>
#include <sys/types.h>
#include <sys/mkdev.h>
#include <sys/kmem.h>
#include <sys/pci.h>
#include <sys/1394/adapters/hci1394.h>
#include <sys/1394/adapters/hci1394_extern.h>
#ifdef _LITTLE_ENDIAN
#define OHCI_SWAP32(DATA) (ddi_swap32(DATA))
#else
#define OHCI_SWAP32(DATA) (DATA)
#endif
static int hci1394_ohci_selfid_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_cfgrom_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_chip_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_phy_resume(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_1394a_init(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_1394a_resume(hci1394_ohci_handle_t ohci_hdl);
static int hci1394_ohci_phy_read_no_lock(hci1394_ohci_handle_t ohci_hdl,
uint_t address, uint_t *data);
static int hci1394_ohci_phy_write_no_lock(hci1394_ohci_handle_t ohci_hdl,
uint_t address, uint_t data);
int
hci1394_ohci_init(hci1394_state_t *soft_state, hci1394_drvinfo_t *drvinfo,
hci1394_ohci_handle_t *ohci_hdl)
{
int status;
uint32_t version;
hci1394_ohci_t *ohci;
#if defined(__x86)
uint16_t cmdreg;
#endif
ASSERT(ohci_hdl != NULL);
ohci = kmem_alloc(sizeof (hci1394_ohci_t), KM_SLEEP);
*ohci_hdl = ohci;
ohci->ohci_bustime_enabled = B_FALSE;
ohci->ohci_bustime_count = 0;
ohci->ohci_set_root_holdoff = B_FALSE;
ohci->ohci_set_gap_count = B_FALSE;
ohci->ohci_gap_count = 0;
mutex_init(&ohci->ohci_mutex, NULL, MUTEX_DRIVER,
drvinfo->di_iblock_cookie);
status = ddi_regs_map_setup(drvinfo->di_dip, OHCI_REG_SET,
(caddr_t *)&ohci->ohci_regs, 0, 0, &drvinfo->di_reg_attr,
&ohci->ohci_reg_handle);
if (status != DDI_SUCCESS) {
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
ohci->soft_state = soft_state;
ohci->ohci_drvinfo = drvinfo;
#if defined(__x86)
cmdreg = pci_config_get16(soft_state->pci_config, PCI_CONF_COMM);
if ((cmdreg & (PCI_COMM_MAE | PCI_COMM_ME)) != (PCI_COMM_MAE |
PCI_COMM_ME)) {
cmdreg |= PCI_COMM_MAE | PCI_COMM_ME;
pci_config_put16(soft_state->pci_config, PCI_CONF_COMM, cmdreg);
}
#endif
status = hci1394_ohci_chip_init(ohci);
if (status != DDI_SUCCESS) {
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
status = hci1394_ohci_phy_init(ohci);
if (status != DDI_SUCCESS) {
(void) hci1394_ohci_soft_reset(ohci);
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
if (ohci->ohci_phy == H1394_PHY_1394A) {
status = hci1394_ohci_1394a_init(ohci);
if (status != DDI_SUCCESS) {
(void) hci1394_ohci_soft_reset(ohci);
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
}
soft_state->halinfo.guid = hci1394_ohci_guid(ohci);
soft_state->halinfo.phy = ohci->ohci_phy;
soft_state->vendor_info.ohci_vendor_id =
ddi_get32(ohci->ohci_reg_handle, &ohci->ohci_regs->vendor_id);
version = ddi_get32(ohci->ohci_reg_handle, &ohci->ohci_regs->version);
soft_state->vendor_info.ohci_version = version;
if (OHCI_VERSION(version) == 0) {
cmn_err(CE_NOTE,
"hci1394(%d): OpenHCI version %x.%x is not supported",
drvinfo->di_instance, OHCI_VERSION(version),
OHCI_REVISION(version));
(void) hci1394_ohci_soft_reset(ohci);
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
status = hci1394_ohci_selfid_init(ohci);
if (status != DDI_SUCCESS) {
(void) hci1394_ohci_soft_reset(ohci);
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
status = hci1394_ohci_cfgrom_init(ohci);
if (status != DDI_SUCCESS) {
(void) hci1394_ohci_soft_reset(ohci);
hci1394_buf_free(&ohci->ohci_selfid_handle);
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
hci1394_ohci_fini(hci1394_ohci_handle_t *ohci_hdl)
{
hci1394_ohci_t *ohci;
ASSERT(ohci_hdl != NULL);
ohci = *ohci_hdl;
(void) hci1394_ohci_soft_reset(ohci);
hci1394_buf_free(&ohci->ohci_cfgrom_handle);
hci1394_buf_free(&ohci->ohci_selfid_handle);
ddi_regs_map_free(&ohci->ohci_reg_handle);
mutex_destroy(&ohci->ohci_mutex);
kmem_free(ohci, sizeof (hci1394_ohci_t));
*ohci_hdl = NULL;
}
static int
hci1394_ohci_chip_init(hci1394_ohci_handle_t ohci_hdl)
{
int status;
ASSERT(ohci_hdl != NULL);
status = hci1394_ohci_soft_reset(ohci_hdl);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_clr, OHCI_HC_NO_BSWAP |
OHCI_HC_POSTWR_ENBL);
if (ohci_hdl->soft_state->swap_data == B_FALSE) {
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_NO_BSWAP |
OHCI_HC_LPS | OHCI_HC_POSTWR_ENBL);
} else {
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_LPS |
OHCI_HC_POSTWR_ENBL);
}
delay(drv_usectohz(hci1394_phy_stabilization_delay_uS));
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_multi_maskhi_clr, 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_multi_masklo_clr, 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_retries, 0x00000002);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->link_ctrl_clr, 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->link_ctrl_set, OHCI_LC_CYC_MAST |
OHCI_LC_CTIME_ENBL | OHCI_LC_RCV_PHY);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phys_upper_bound, (uint32_t)0x0000FFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_req_filterhi_set, (uint32_t)0x80000000);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_event_clr, (uint32_t)0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_mask_clr, (uint32_t)0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_event_clr, (uint32_t)0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_mask_clr, (uint32_t)0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_event_clr, (uint32_t)0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_mask_clr, (uint32_t)0xFFFFFFFF);
return (DDI_SUCCESS);
}
int
hci1394_ohci_soft_reset(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t resetStatus;
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_SOFT_RESET);
drv_usecwait(OHCI_CHIP_RESET_TIME_IN_uSEC);
resetStatus = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set);
resetStatus = resetStatus & OHCI_HC_SOFT_RESET;
if (resetStatus != 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
void
hci1394_ohci_reg_read(hci1394_ohci_handle_t ohci_hdl,
uint_t offset, uint32_t *data)
{
uint32_t *addr;
ASSERT(ohci_hdl != NULL);
ASSERT(data != NULL);
addr = (uint32_t *)((uintptr_t)ohci_hdl->ohci_regs +
(uintptr_t)(offset & OHCI_REG_ADDR_MASK));
*data = ddi_get32(ohci_hdl->ohci_reg_handle, addr);
}
void
hci1394_ohci_reg_write(hci1394_ohci_handle_t ohci_hdl,
uint_t offset, uint32_t data)
{
uint32_t *addr;
ASSERT(ohci_hdl != NULL);
addr = (uint32_t *)((uintptr_t)ohci_hdl->ohci_regs +
(uintptr_t)(offset & OHCI_REG_ADDR_MASK));
ddi_put32(ohci_hdl->ohci_reg_handle, addr, data);
}
void
hci1394_ohci_intr_master_enable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_mask_set, OHCI_INTR_MASTER_INTR_ENBL);
}
void
hci1394_ohci_intr_master_disable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_mask_clr, OHCI_INTR_MASTER_INTR_ENBL);
}
uint32_t
hci1394_ohci_intr_asserted(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t interrupts_asserted;
ASSERT(ohci_hdl != NULL);
interrupts_asserted = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_event_clr);
return (interrupts_asserted);
}
void
hci1394_ohci_intr_enable(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_mask_set, interrupt_mask);
}
void
hci1394_ohci_intr_disable(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_mask_clr, interrupt_mask);
}
void
hci1394_ohci_intr_clear(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_event_clr, interrupt_mask);
}
uint32_t
hci1394_ohci_it_intr_asserted(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t interrupts_asserted;
ASSERT(ohci_hdl != NULL);
interrupts_asserted = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_event_clr);
return (interrupts_asserted);
}
void
hci1394_ohci_it_intr_enable(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_mask_set, interrupt_mask);
}
void
hci1394_ohci_it_intr_disable(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_mask_clr, interrupt_mask);
}
void
hci1394_ohci_it_intr_clear(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_event_clr, interrupt_mask);
}
int
hci1394_ohci_it_ctxt_count_get(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t channel_mask;
int count;
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_mask_set, 0xFFFFFFFF);
channel_mask = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it_intr_mask_set);
count = 0;
while (channel_mask != 0) {
channel_mask = channel_mask >> 1;
count++;
}
return (count);
}
void
hci1394_ohci_it_cmd_ptr_set(hci1394_ohci_handle_t ohci_hdl,
uint_t context_number, uint32_t io_addr)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->it[context_number].cmd_ptrlo,
io_addr);
}
uint32_t
hci1394_ohci_ir_intr_asserted(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t interrupts_asserted;
ASSERT(ohci_hdl != NULL);
interrupts_asserted = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_event_clr);
return (interrupts_asserted);
}
void
hci1394_ohci_ir_intr_enable(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_mask_set, interrupt_mask);
}
void
hci1394_ohci_ir_intr_disable(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_mask_clr, interrupt_mask);
}
void
hci1394_ohci_ir_intr_clear(hci1394_ohci_handle_t ohci_hdl,
uint32_t interrupt_mask)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_event_clr, interrupt_mask);
}
int
hci1394_ohci_ir_ctxt_count_get(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t channel_mask;
int count;
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_mask_set, 0xFFFFFFFF);
channel_mask = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir_intr_mask_set);
count = 0;
while (channel_mask != 0) {
channel_mask = channel_mask >> 1;
count++;
}
return (count);
}
void
hci1394_ohci_ir_cmd_ptr_set(hci1394_ohci_handle_t ohci_hdl,
uint_t context_number, uint32_t io_addr)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ir[context_number].cmd_ptrlo,
io_addr);
}
void
hci1394_ohci_link_enable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_LINK_ENBL);
}
void
hci1394_ohci_link_disable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_clr, OHCI_HC_LINK_ENBL);
}
int
hci1394_ohci_bus_reset(hci1394_ohci_handle_t ohci_hdl)
{
int status;
uint_t reg;
ASSERT(ohci_hdl != NULL);
reg = OHCI_PHY_IBR;
if (ohci_hdl->ohci_set_root_holdoff == B_TRUE) {
reg = reg | OHCI_PHY_RHB;
}
if (ohci_hdl->ohci_set_gap_count == B_TRUE) {
reg = reg | ohci_hdl->ohci_gap_count;
} else {
reg = reg | OHCI_PHY_MAX_GAP;
}
status = hci1394_ohci_phy_write(ohci_hdl, 0x1, reg);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ohci_hdl->ohci_set_root_holdoff = B_FALSE;
ohci_hdl->ohci_set_gap_count = B_FALSE;
return (DDI_SUCCESS);
}
int
hci1394_ohci_bus_reset_nroot(hci1394_ohci_handle_t ohci_hdl)
{
int status;
uint_t reg;
ASSERT(ohci_hdl != NULL);
(void) hci1394_ohci_phy_read(ohci_hdl, 0x1, ®);
reg = reg | OHCI_PHY_IBR;
reg = reg & ~OHCI_PHY_RHB;
status = hci1394_ohci_phy_write(ohci_hdl, 0x1, reg);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_init(hci1394_ohci_handle_t ohci_hdl)
{
int status;
uint_t phy_reg;
ASSERT(ohci_hdl != NULL);
status = hci1394_ohci_phy_read(ohci_hdl, 2, &phy_reg);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
if ((phy_reg & OHCI_PHY_EXTND_MASK) != OHCI_PHY_EXTND) {
ohci_hdl->ohci_phy = H1394_PHY_1995;
} else {
ohci_hdl->ohci_phy = H1394_PHY_1394A;
}
return (DDI_SUCCESS);
}
static int
hci1394_ohci_phy_resume(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_set(hci1394_ohci_handle_t ohci_hdl, uint_t address,
uint_t bits)
{
int status;
uint_t reg;
ASSERT(ohci_hdl != NULL);
mutex_enter(&ohci_hdl->ohci_mutex);
status = hci1394_ohci_phy_read_no_lock(ohci_hdl, address, ®);
if (status != DDI_SUCCESS) {
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_FAILURE);
}
reg = reg | bits;
status = hci1394_ohci_phy_write_no_lock(ohci_hdl, address, reg);
if (status != DDI_SUCCESS) {
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_FAILURE);
}
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_clr(hci1394_ohci_handle_t ohci_hdl, uint_t address,
uint_t bits)
{
int status;
uint_t reg;
ASSERT(ohci_hdl != NULL);
mutex_enter(&ohci_hdl->ohci_mutex);
status = hci1394_ohci_phy_read_no_lock(ohci_hdl, address, ®);
if (status != DDI_SUCCESS) {
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_FAILURE);
}
reg = reg & ~bits;
status = hci1394_ohci_phy_write_no_lock(ohci_hdl, address, reg);
if (status != DDI_SUCCESS) {
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_FAILURE);
}
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_read(hci1394_ohci_handle_t ohci_hdl, uint_t address,
uint_t *data)
{
int status;
ASSERT(ohci_hdl != NULL);
mutex_enter(&ohci_hdl->ohci_mutex);
status = hci1394_ohci_phy_read_no_lock(ohci_hdl, address, data);
mutex_exit(&ohci_hdl->ohci_mutex);
return (status);
}
int
hci1394_ohci_phy_write(hci1394_ohci_handle_t ohci_hdl, uint_t address,
uint_t data)
{
int status;
ASSERT(ohci_hdl != NULL);
mutex_enter(&ohci_hdl->ohci_mutex);
status = hci1394_ohci_phy_write_no_lock(ohci_hdl, address, data);
mutex_exit(&ohci_hdl->ohci_mutex);
return (status);
}
static int
hci1394_ohci_phy_read_no_lock(hci1394_ohci_handle_t ohci_hdl, uint_t address,
uint_t *data)
{
uint32_t ohci_reg;
int count;
ASSERT(ohci_hdl != NULL);
ASSERT(data != NULL);
ASSERT(MUTEX_HELD(&ohci_hdl->ohci_mutex));
if (address == 0) {
return (DDI_FAILURE);
}
ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phy_ctrl);
if ((ohci_reg & (OHCI_PHYC_RDREG | OHCI_PHYC_WRREG)) != 0) {
return (DDI_FAILURE);
}
ohci_reg = OHCI_PHYC_RDREG | ((address & 0xF) <<
OHCI_PHYC_REGADDR_SHIFT);
ddi_put32(ohci_hdl->ohci_reg_handle, &ohci_hdl->ohci_regs->phy_ctrl,
ohci_reg);
count = 0;
while (count < hci1394_phy_delay_uS) {
ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phy_ctrl);
if ((ohci_reg & OHCI_PHYC_RDDONE) != 0) {
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_event_clr,
OHCI_INTR_PHY_REG_RCVD);
break;
}
drv_usecwait(1);
count++;
}
if (count >= hci1394_phy_delay_uS) {
*data = 0;
return (DDI_FAILURE);
}
*data = (ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phy_ctrl) & OHCI_PHYC_RDDATA_MASK) >>
OHCI_PHYC_RDDATA_SHIFT;
return (DDI_SUCCESS);
}
static int
hci1394_ohci_phy_write_no_lock(hci1394_ohci_handle_t ohci_hdl, uint_t address,
uint_t data)
{
uint32_t ohci_reg;
int count;
ASSERT(ohci_hdl != NULL);
ASSERT(MUTEX_HELD(&ohci_hdl->ohci_mutex));
if (address == 0) {
return (DDI_FAILURE);
}
ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phy_ctrl);
if ((ohci_reg & (OHCI_PHYC_RDREG | OHCI_PHYC_WRREG)) != 0) {
return (DDI_FAILURE);
}
ohci_reg = OHCI_PHYC_WRREG | ((address & 0xF) <<
OHCI_PHYC_REGADDR_SHIFT) | (data & OHCI_PHYC_WRDATA_MASK);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phy_ctrl, ohci_reg);
count = 0;
while (count < hci1394_phy_delay_uS) {
ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phy_ctrl);
if ((ohci_reg & OHCI_PHYC_WRREG) == 0) {
break;
}
drv_usecwait(1);
count++;
}
if (count >= hci1394_phy_delay_uS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_info(hci1394_ohci_handle_t ohci_hdl, uint32_t *info)
{
int status;
uint32_t phy_info;
uint32_t reg;
int index;
int num_ports;
int count;
uint32_t port_status;
ASSERT(ohci_hdl != NULL);
ASSERT(info != NULL);
ASSERT(ohci_hdl->ohci_phy == H1394_PHY_1995);
phy_info = 0x80400000;
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->node_id);
phy_info = phy_info | ((reg << IEEE1394_SELFID_PHYID_SHIFT) &
IEEE1394_SELFID_PHYID_MASK);
status = hci1394_ohci_phy_read(ohci_hdl, 1, ®);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
phy_info = phy_info | ((reg << IEEE1394_SELFID_GAP_CNT_SHIFT) &
IEEE1394_SELFID_GAP_CNT_MASK);
status = hci1394_ohci_phy_read(ohci_hdl, 2, ®);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
phy_info = phy_info | ((reg & 0xC0) << 8);
num_ports = reg & 0x1F;
if (num_ports == 0) {
return (DDI_FAILURE);
}
count = 0;
for (index = 0; index < 3; index++) {
if (num_ports > 0) {
status = hci1394_ohci_phy_read(ohci_hdl,
count + 3, ®);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
if ((reg & 0x04) == 0) {
port_status =
IEEE1394_SELFID_PORT_NOT_CONNECTED;
} else if ((reg & 0x08) == 0) {
port_status = IEEE1394_SELFID_PORT_TO_PARENT;
} else {
port_status = IEEE1394_SELFID_PORT_TO_CHILD;
}
num_ports--;
} else {
port_status = IEEE1394_SELFID_PORT_NO_PORT;
}
phy_info = phy_info | (port_status << (6 - (index * 2)));
count++;
}
*info = phy_info;
return (DDI_SUCCESS);
}
uint_t
hci1394_ohci_current_busgen(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
uint_t generation_count;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->self_id_count);
generation_count = (reg & OHCI_SLFC_GEN_MASK) >> OHCI_SLFC_GEN_SHIFT;
return (generation_count);
}
int
hci1394_ohci_startup(hci1394_ohci_handle_t ohci_hdl)
{
int status;
ASSERT(ohci_hdl != NULL);
hci1394_ohci_link_enable(ohci_hdl);
status = hci1394_ohci_bus_reset(ohci_hdl);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
hci1394_isr_mask_setup(ohci_hdl->soft_state);
hci1394_ohci_intr_master_enable(ohci_hdl);
return (DDI_SUCCESS);
}
void
hci1394_ohci_postwr_addr(hci1394_ohci_handle_t ohci_hdl, uint64_t *addr)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
ASSERT(addr != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->posted_write_addrhi);
*addr = ((uint64_t)reg) << 32;
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->posted_write_addrlo);
*addr = *addr | (uint64_t)reg;
hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_POST_WR_ERR);
}
uint64_t
hci1394_ohci_guid(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
uint64_t guid;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->guid_hi);
guid = ((uint64_t)reg) << 32;
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->guid_lo);
guid = guid | (uint64_t)reg;
return (guid);
}
int
hci1394_ohci_csr_read(hci1394_ohci_handle_t ohci_hdl, uint_t offset,
uint32_t *data)
{
uint_t generation;
int status;
ASSERT(ohci_hdl != NULL);
ASSERT(data != NULL);
generation = hci1394_ohci_current_busgen(ohci_hdl);
status = hci1394_ohci_csr_cswap(ohci_hdl, generation, offset, 0, 0,
data);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_csr_cswap(hci1394_ohci_handle_t ohci_hdl, uint_t generation,
uint_t offset, uint32_t compare, uint32_t swap, uint32_t *old)
{
int count;
uint32_t ohci_reg;
ASSERT(ohci_hdl != NULL);
ASSERT(old != NULL);
if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
return (DDI_FAILURE);
}
mutex_enter(&ohci_hdl->ohci_mutex);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->csr_data, swap);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->csr_compare_data, compare);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->csr_ctrl, offset & OHCI_CSR_SELECT);
count = 0;
while (count < 2) {
ohci_reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->csr_ctrl);
if ((ohci_reg & OHCI_CSR_DONE) != 0) {
break;
}
drv_usecwait(1);
count++;
}
if (count >= 2) {
*old = 0;
mutex_exit(&ohci_hdl->ohci_mutex);
return (DDI_FAILURE);
}
*old = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->csr_data);
mutex_exit(&ohci_hdl->ohci_mutex);
if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
if (*old == compare) {
(void) hci1394_ohci_bus_reset(ohci_hdl);
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_contender_enable(hci1394_ohci_handle_t ohci_hdl)
{
int status;
ASSERT(ohci_hdl != NULL);
if (ohci_hdl->ohci_phy == H1394_PHY_1995) {
return (DDI_FAILURE);
}
status = hci1394_ohci_phy_set(ohci_hdl, 0x4, OHCI_PHY_CNTDR);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_root_holdoff_enable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ohci_hdl->ohci_set_root_holdoff = B_TRUE;
return (DDI_SUCCESS);
}
int
hci1394_ohci_gap_count_set(hci1394_ohci_handle_t ohci_hdl, uint_t gap_count)
{
ASSERT(ohci_hdl != NULL);
ohci_hdl->ohci_set_gap_count = B_TRUE;
ohci_hdl->ohci_gap_count = gap_count & OHCI_PHY_MAX_GAP;
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_filter_set(hci1394_ohci_handle_t ohci_hdl, uint64_t mask,
uint_t generation)
{
uint32_t data;
ASSERT(ohci_hdl != NULL);
if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
return (DDI_FAILURE);
}
data = (uint32_t)((mask >> 32) & 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phys_req_filterhi_set, data);
data = (uint32_t)(mask & 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phys_req_filterlo_set, data);
if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
(void) hci1394_ohci_bus_reset(ohci_hdl);
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_phy_filter_clr(hci1394_ohci_handle_t ohci_hdl,
uint64_t mask, uint_t generation)
{
uint32_t data;
ASSERT(ohci_hdl != NULL);
if (generation != hci1394_ohci_current_busgen(ohci_hdl)) {
return (DDI_FAILURE);
}
data = (uint32_t)((mask >> 32) & 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phys_req_filterhi_clr, data);
data = (uint32_t)(mask & 0xFFFFFFFF);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->phys_req_filterlo_clr, data);
return (DDI_SUCCESS);
}
int
hci1394_ohci_bus_reset_short(hci1394_ohci_handle_t ohci_hdl)
{
int status;
ASSERT(ohci_hdl != NULL);
if (ohci_hdl->ohci_phy == H1394_PHY_1995) {
return (DDI_FAILURE);
}
status = hci1394_ohci_phy_set(ohci_hdl, 0x5, OHCI_PHY_ISBR);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
return (status);
}
void
hci1394_ohci_cfgrom_update(hci1394_ohci_handle_t ohci_hdl, void *local_buf,
uint_t quadlet_count)
{
uint32_t *data;
ASSERT(ohci_hdl != NULL);
ASSERT(local_buf != NULL);
data = (uint32_t *)local_buf;
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->config_rom_hdr, 0);
ddi_rep_put8(ohci_hdl->ohci_cfgrom.bi_handle, local_buf,
(uint8_t *)ohci_hdl->ohci_cfgrom.bi_kaddr, quadlet_count << 2,
DDI_DEV_AUTOINCR);
(void) ddi_dma_sync(ohci_hdl->ohci_cfgrom.bi_dma_handle, 0,
quadlet_count << 2, DDI_DMA_SYNC_FORDEV);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->bus_options, OHCI_SWAP32(data[2]));
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->config_rom_hdr, OHCI_SWAP32(data[0]));
}
void
hci1394_ohci_nodeid_get(hci1394_ohci_handle_t ohci_hdl, uint_t *nodeid)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
ASSERT(nodeid != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->node_id);
*nodeid = (reg & 0xFFFF) << 16;
}
void
hci1394_ohci_nodeid_set(hci1394_ohci_handle_t ohci_hdl, uint_t nodeid)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
reg = ((nodeid & 0xFFC00000) >> 16);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->node_id, reg);
}
void
hci1394_ohci_nodeid_info(hci1394_ohci_handle_t ohci_hdl, uint_t *nodeid,
boolean_t *error)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
ASSERT(nodeid != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->node_id);
*nodeid = reg & 0xFFFF;
if ((reg & OHCI_NDID_IDVALID) == 0) {
*error = B_TRUE;
} else {
*error = B_FALSE;
}
}
void
hci1394_ohci_cycletime_get(hci1394_ohci_handle_t ohci_hdl,
uint32_t *cycle_time)
{
ASSERT(ohci_hdl != NULL);
ASSERT(cycle_time != NULL);
*cycle_time = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->isoch_cycle_timer);
}
void
hci1394_ohci_cycletime_set(hci1394_ohci_handle_t ohci_hdl,
uint32_t cycle_time)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->isoch_cycle_timer, cycle_time);
}
void
hci1394_ohci_bustime_get(hci1394_ohci_handle_t ohci_hdl, uint32_t *bus_time)
{
uint32_t bus_time1;
uint32_t bus_time2;
uint32_t cycle_time;
ASSERT(ohci_hdl != NULL);
ASSERT(bus_time != NULL);
do {
bus_time1 = ohci_hdl->ohci_bustime_count;
cycle_time = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->isoch_cycle_timer);
bus_time2 = ohci_hdl->ohci_bustime_count;
} while (bus_time1 != bus_time2);
*bus_time = (bus_time2 << 7) | (cycle_time >> 25);
}
void
hci1394_ohci_bustime_set(hci1394_ohci_handle_t ohci_hdl, uint32_t bus_time)
{
ASSERT(ohci_hdl != NULL);
if (ohci_hdl->ohci_bustime_enabled == B_FALSE) {
ohci_hdl->ohci_bustime_enabled = B_TRUE;
hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_CYC_64_SECS);
hci1394_ohci_intr_enable(ohci_hdl, OHCI_INTR_CYC_64_SECS);
}
ohci_hdl->ohci_bustime_count = (bus_time >> 7);
}
void
hci1394_ohci_atreq_retries_get(hci1394_ohci_handle_t ohci_hdl,
uint_t *atreq_retries)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
ASSERT(atreq_retries != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_retries);
*atreq_retries = reg & OHCI_RET_MAX_ATREQ_MASK;
}
void
hci1394_ohci_atreq_retries_set(hci1394_ohci_handle_t ohci_hdl,
uint_t atreq_retries)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
mutex_enter(&ohci_hdl->ohci_mutex);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_retries);
reg = reg & ~OHCI_RET_MAX_ATREQ_MASK;
reg = reg | (atreq_retries & OHCI_RET_MAX_ATREQ_MASK);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_retries, reg);
mutex_exit(&ohci_hdl->ohci_mutex);
}
void
hci1394_ohci_isr_cycle64seconds(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t cycle_time;
ASSERT(ohci_hdl != NULL);
hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_CYC_64_SECS);
cycle_time = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->isoch_cycle_timer);
if ((cycle_time & 0x80000000) == 0) {
ohci_hdl->ohci_bustime_count++;
}
}
void
hci1394_ohci_isr_phy(hci1394_ohci_handle_t ohci_hdl)
{
uint_t phy_status;
int status;
ASSERT(ohci_hdl != NULL);
hci1394_ohci_intr_clear(ohci_hdl, OHCI_INTR_PHY);
ohci_hdl->ohci_drvinfo->di_stats.st_phy_isr++;
if (ohci_hdl->ohci_phy == H1394_PHY_1995) {
return;
}
status = hci1394_ohci_phy_read(ohci_hdl, 5, &phy_status);
if (status != DDI_SUCCESS) {
return;
}
if (phy_status & OHCI_PHY_LOOP_ERR) {
ohci_hdl->ohci_drvinfo->di_stats.st_phy_loop_err++;
cmn_err(CE_NOTE, "hci1394(%d): ERROR - bus loop detected",
ohci_hdl->ohci_drvinfo->di_instance);
}
if (phy_status & OHCI_PHY_PWRFAIL_ERR) {
ohci_hdl->ohci_drvinfo->di_stats.st_phy_pwrfail_err++;
}
if (phy_status & OHCI_PHY_TIMEOUT_ERR) {
ohci_hdl->ohci_drvinfo->di_stats.st_phy_timeout_err++;
}
if (phy_status & OHCI_PHY_PORTEVT_ERR) {
ohci_hdl->ohci_drvinfo->di_stats.st_phy_portevt_err++;
}
status = hci1394_ohci_phy_write(ohci_hdl, 5, phy_status);
if (status != DDI_SUCCESS) {
return;
}
hci1394_ohci_intr_disable(ohci_hdl, OHCI_INTR_PHY);
}
boolean_t
hci1394_ohci_root_check(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
int status;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->node_id);
if ((reg & OHCI_REG_NODEID_ROOT) && (reg & OHCI_NDID_IDVALID)) {
status = B_TRUE;
} else {
status = B_FALSE;
}
return (status);
}
boolean_t
hci1394_ohci_cmc_check(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
int status;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->bus_options);
if (reg & OHCI_REG_BUSOPTIONS_CMC) {
status = B_TRUE;
} else {
status = B_FALSE;
}
return (status);
}
void
hci1394_ohci_cycle_master_enable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->intr_event_clr, OHCI_INTR_CYC_TOO_LONG);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->link_ctrl_set, OHCI_LC_CYC_MAST);
}
void
hci1394_ohci_cycle_master_disable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->link_ctrl_clr, OHCI_LC_CYC_MAST);
}
int
hci1394_ohci_resume(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t quadlet;
int status;
ASSERT(ohci_hdl != NULL);
status = hci1394_ohci_chip_init(ohci_hdl);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
status = hci1394_ohci_phy_resume(ohci_hdl);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
status = hci1394_ohci_1394a_resume(ohci_hdl);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->config_rom_maplo,
(uint32_t)ohci_hdl->ohci_cfgrom.bi_cookie.dmac_address);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->self_id_buflo,
(uint32_t)ohci_hdl->ohci_selfid.bi_cookie.dmac_address);
hci1394_ohci_selfid_enable(ohci_hdl);
ddi_rep_get8(ohci_hdl->ohci_cfgrom.bi_handle, (uint8_t *)&quadlet,
&((uint8_t *)ohci_hdl->ohci_cfgrom.bi_kaddr)[8], 4,
DDI_DEV_AUTOINCR);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->bus_options, OHCI_SWAP32(quadlet));
ddi_rep_get8(ohci_hdl->ohci_cfgrom.bi_handle, (uint8_t *)&quadlet,
&((uint8_t *)ohci_hdl->ohci_cfgrom.bi_kaddr)[0], 4,
DDI_DEV_AUTOINCR);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->config_rom_hdr, OHCI_SWAP32(quadlet));
return (DDI_SUCCESS);
}
static int
hci1394_ohci_selfid_init(hci1394_ohci_handle_t ohci_hdl)
{
hci1394_buf_parms_t parms;
int status;
ASSERT(ohci_hdl != NULL);
parms.bp_length = 2048;
parms.bp_max_cookies = 1;
parms.bp_alignment = 2048;
status = hci1394_buf_alloc(ohci_hdl->ohci_drvinfo, &parms,
&ohci_hdl->ohci_selfid, &ohci_hdl->ohci_selfid_handle);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->self_id_buflo,
(uint32_t)ohci_hdl->ohci_selfid.bi_cookie.dmac_address);
hci1394_ohci_selfid_enable(ohci_hdl);
return (DDI_SUCCESS);
}
void
hci1394_ohci_selfid_enable(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->link_ctrl_set, OHCI_LC_RCV_SELF);
}
void
hci1394_ohci_selfid_read(hci1394_ohci_handle_t ohci_hdl, uint_t offset,
uint32_t *data)
{
ASSERT(ohci_hdl != NULL);
ASSERT(data != NULL);
*data = ddi_get32(ohci_hdl->ohci_selfid.bi_handle,
&((uint32_t *)ohci_hdl->ohci_selfid.bi_kaddr)[offset]);
}
void
hci1394_ohci_selfid_info(hci1394_ohci_handle_t ohci_hdl, uint_t *busgen,
uint_t *size, boolean_t *error)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
ASSERT(busgen != NULL);
ASSERT(size != NULL);
ASSERT(error != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->self_id_count);
*busgen = (reg & OHCI_SLFC_GEN_MASK) >> OHCI_SLFC_GEN_SHIFT;
*size = reg & OHCI_SLFC_NUM_QUADS_MASK;
if ((reg & OHCI_SLFC_ERROR) == 0) {
*error = B_FALSE;
} else {
*error = B_TRUE;
}
}
boolean_t
hci1394_ohci_selfid_buf_current(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
int status;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_selfid.bi_handle,
&((uint32_t *)ohci_hdl->ohci_selfid.bi_kaddr)[0]);
if (ohci_hdl->ohci_drvinfo->di_gencnt != ((reg & OHCI_SLFC_GEN_MASK) >>
OHCI_SLFC_GEN_SHIFT)) {
status = B_FALSE;
} else {
status = B_TRUE;
}
return (status);
}
void
hci1394_ohci_selfid_sync(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
(void) ddi_dma_sync(ohci_hdl->ohci_selfid.bi_dma_handle, 0,
ohci_hdl->ohci_selfid.bi_length, DDI_DMA_SYNC_FORKERNEL);
}
static int
hci1394_ohci_cfgrom_init(hci1394_ohci_handle_t ohci_hdl)
{
hci1394_buf_parms_t parms;
int status;
ASSERT(ohci_hdl != NULL);
parms.bp_length = 1024;
parms.bp_max_cookies = 1;
parms.bp_alignment = 1024;
status = hci1394_buf_alloc(ohci_hdl->ohci_drvinfo, &parms,
&ohci_hdl->ohci_cfgrom, &ohci_hdl->ohci_cfgrom_handle);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->config_rom_maplo,
(uint32_t)ohci_hdl->ohci_cfgrom.bi_cookie.dmac_address);
return (DDI_SUCCESS);
}
void
hci1394_ohci_bus_capabilities(hci1394_ohci_handle_t ohci_hdl,
uint32_t *bus_capabilities)
{
ASSERT(ohci_hdl != NULL);
*bus_capabilities = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->bus_options) | (OHCI_BOPT_IRMC |
OHCI_BOPT_CMC | OHCI_BOPT_ISC);
}
boolean_t
hci1394_ohci_at_active(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_req.ctxt_ctrl_set);
if (reg & OHCI_CC_ACTIVE_MASK) {
return (B_TRUE);
}
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_set);
if (reg & OHCI_CC_ACTIVE_MASK) {
return (B_TRUE);
}
return (B_FALSE);
}
void
hci1394_ohci_atreq_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_req.cmd_ptrlo, cmdptr);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_req.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_atreq_wake(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_req.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}
void
hci1394_ohci_atreq_stop(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_req.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_arresp_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_resp.cmd_ptrlo, cmdptr);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_resp.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_arresp_wake(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_resp.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}
void
hci1394_ohci_arresp_stop(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_resp.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_arreq_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_req.cmd_ptrlo, cmdptr);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_req.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_arreq_wake(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_req.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}
void
hci1394_ohci_arreq_stop(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->ar_req.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_atresp_start(hci1394_ohci_handle_t ohci_hdl, uint32_t cmdptr)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_resp.cmd_ptrlo, cmdptr);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_set, OHCI_CC_RUN_MASK);
}
void
hci1394_ohci_atresp_wake(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_set, OHCI_CC_WAKE_MASK);
}
void
hci1394_ohci_atresp_stop(hci1394_ohci_handle_t ohci_hdl)
{
ASSERT(ohci_hdl != NULL);
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->at_resp.ctxt_ctrl_clr, OHCI_CC_RUN_MASK);
}
int
hci1394_ohci_1394a_init(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
int status;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set);
if (reg & OHCI_HC_PROG_PHY_ENBL) {
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_APHY_ENBL);
status = hci1394_ohci_phy_set(ohci_hdl, 5,
(OHCI_PHY_ENBL_ACCEL | OHCI_PHY_ENBL_MULTI));
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
int
hci1394_ohci_1394a_resume(hci1394_ohci_handle_t ohci_hdl)
{
uint32_t reg;
int status;
ASSERT(ohci_hdl != NULL);
reg = ddi_get32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set);
if (reg & OHCI_HC_PROG_PHY_ENBL) {
ddi_put32(ohci_hdl->ohci_reg_handle,
&ohci_hdl->ohci_regs->hc_ctrl_set, OHCI_HC_APHY_ENBL);
status = hci1394_ohci_phy_set(ohci_hdl, 5,
(OHCI_PHY_ENBL_ACCEL | OHCI_PHY_ENBL_MULTI));
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}