iBoot/drivers/apple/ausb/ausb.c

254 lines
6.2 KiB
C

/*
* Copyright (C) 2011-2014 Apple Inc. All rights reserved.
*
* This document is the property of Apple Inc.
* It is considered confidential and proprietary.
*
* This document may not be reproduced or transmitted in any form,
* in whole or in part, without the express written permission of
* Apple Inc.
*/
#include <debug.h>
#include <lib/devicetree.h>
#include <platform.h>
#include <platform/soc/hwclocks.h>
#include <platform/usbconfig.h>
#include <platform/soc/chipid.h>
#include <sys.h>
#include "ausb.h"
// USB Widget related constants
#if !AUSB_USB20PHY_ONLY_VERSION
#if APPLICATION_IBOOT && (PRODUCT_IBOOT || PRODUCT_IBEC)
static const uint32_t high_addr_bits = (1 << 8) | ((SDRAM_BASE >> 32) & 0xf);
#elif APPLICATION_SECUREROM || (APPLICATION_IBOOT && WITH_DFU_MODE)
static const uint32_t high_addr_bits = (1 << 8) | ((SRAM_BASE >> 32) & 0xf);
#else
#error Not Supported
#endif
#endif
///////////////////////////////////////////////////////////
//
// USB PHY Control
//
///////////////////////////////////////////////////////////
static bool usbphy_powered;
void usbphy_power_up(void)
{
if (usbphy_powered)
return;
clock_gate(CLK_USB, true);
clock_gate(CLK_USBCTLREG, true);
clock_gate(CLK_USB_OTG, true);
#if !AUSB_USB20PHY_ONLY_VERSION
// Set the USB OTG Widget register
rAUSB_WIDGET_OTG_ADDR = high_addr_bits;
#endif
// * expects SIDDQ and VBUSVLDEXTSEL set to 1 out of reset.
// * program tuning values
rAUSB_USB20PHY_CFG0 = USBPHY_OTGTUNE0;
#if defined(USBPHY_OTGTUNE1)
rAUSB_USB20PHY_CFG1 = USBPHY_OTGTUNE1;
#endif
// <rdar://problem/15495710> ECO_216: Add register control to FSEL of USB PiCOPHY to get better jitter performance
// The bit USB20PHY_CFG1::PLLBTUNE needs to be set for Fiji revisions > A0 and all Capri revisions
#if defined(SUB_PLATFORM_T7000) || defined(SUB_PLATFORM_T7001)
rAUSB_USB20PHY_CFG1 |= (1 << 2);
#endif
// <rdar://problem/16373379> Fiji >= B1 and Capri >= A1 need to adjust USB20PHY_CFG1:PLLITUNE
#if defined(SUB_PLATFORM_T7000)
if(platform_get_chip_revision() >= CHIP_REVISION_B1)
rAUSB_USB20PHY_CFG1 |= (2 << 4);
#endif
#if defined(SUB_PLATFORM_T7001)
if(platform_get_chip_revision() >= CHIP_REVISION_A1)
rAUSB_USB20PHY_CFG1 |= (2 << 4);
#endif
// Maui A0/A1 uses different tunable than >= B0
#if defined(SUB_PLATFORM_S8000)
if(platform_get_chip_revision() <= CHIP_REVISION_A1)
rAUSB_USB20PHY_CFG0 = USBPHY_OTGTUNE0_AX;
#endif
// * assert PHY_RESET
rAUSB_USB20PHY_CTL |= (1 << 0);
// * clear analog power-down (SIDDQ) and otg-block power-down bits
rAUSB_USB20PHY_CTL &= ~((1 << 3) | (1 << 2));
// * wait 10us delay
spin(10);
// * de-assert PHY_RESET
rAUSB_USB20PHY_CTL &= ~(1 << 0);
// * wait 1000us delay: This wait for PLL to be locked after POR.
spin(1000);
usbphy_powered = true;
}
void usbphy_enable_pullup(void)
{
if (!usbphy_powered)
return;
// Enable D+ PU
rAUSB_USB20PHY_OTGSIG |= (1 << 1);
}
void usbphy_power_down(void)
{
if (!usbphy_powered)
return;
// * Assert PHY_RESET
rAUSB_USB20PHY_CTL |= (1 << 0);
// * disable D+ PU
rAUSB_USB20PHY_OTGSIG &= ~(1 << 1);
// * wait 10us delay
spin(10);
// * De-assert PHY_RESET
rAUSB_USB20PHY_CTL &= ~(1 << 0);
// * wait 1000us delay: This wait for PLL to be locked after POR.
spin(1000);
// * set analog and otg block power down bits
rAUSB_USB20PHY_CTL |= ((1 << 3) | (1 << 2));
clock_gate(CLK_USB_OTG, false);
clock_gate(CLK_USBCTLREG, false);
clock_gate(CLK_USB, false);
usbphy_powered = false;
}
bool usbphy_is_cable_connected(void)
{
bool connected;
if (!usbphy_powered) {
clock_gate(CLK_USB, true);
clock_gate(CLK_USBCTLREG, true);
}
connected = (rAUSB_USB20PHY_OTGSIG & (1 << 8)) != 0;
if (!usbphy_powered) {
clock_gate(CLK_USBCTLREG, false);
clock_gate(CLK_USB, false);
}
return connected;
}
bool usbphy_set_dpdm_monitor(int select)
{
// XXX IBOOT64_TODO
return false;
}
#if WITH_DEVICETREE
void update_devicetree_property(DTNode *node, char * propName, uint32_t value, bool doOR)
{
void *propData;
uint32_t propSize;
if (FindProperty(node, &propName, &propData, &propSize)) {
if (propSize >= sizeof(uint32_t)) {
if(doOR) {
*(uint32_t *)propData |= value;
}
else {
*(uint32_t *)propData = value;
}
}
}
}
void usbphy_update_device_tree(DTNode *node)
{
uint32_t phy_tuning_val;
phy_tuning_val = 0;
#ifdef USBPHY_UOTGTUNE
phy_tuning_val = USBPHY_UOTGTUNE;
#endif
// Fill in the phy-tuning-val property
update_devicetree_property(node, "phy-tuning-val", phy_tuning_val, false);
// <rdar://problem/15495710> ECO_216: Add register control to FSEL of USB PiCOPHY to get better jitter performance
// The bit USB20PHY_CFG1::PLLBTUNE needs to be set for Fiji revisions > A0 and all Capri revisions
#if defined(SUB_PLATFORM_T7000) || defined(SUB_PLATFORM_T7001)
update_devicetree_property(node, "cfg1-device", (1 << 2), true);
update_devicetree_property(node, "cfg1-host", (1 << 2), true);
#endif
// <rdar://problem/16373379> Fiji >= B1 and Capri >= A1 need to adjust USB20PHY_CFG1:PLLITUNE
#if defined(SUB_PLATFORM_T7000)
if(platform_get_chip_revision() >= CHIP_REVISION_B1) {
update_devicetree_property(node, "cfg1-device", (2 << 4), true);
update_devicetree_property(node, "cfg1-host", (2 << 4), true);
}
#endif
#if defined(SUB_PLATFORM_T7001)
if(platform_get_chip_revision() >= CHIP_REVISION_A1) {
update_devicetree_property(node, "cfg1-device", (2 << 4), true);
update_devicetree_property(node, "cfg1-host", (2 << 4), true);
}
#endif
// Maui A0/A1 uses different tunable than >= B0
#if defined(SUB_PLATFORM_S8000)
if(platform_get_chip_revision() <= CHIP_REVISION_A1) {
update_devicetree_property(node, "cfg0-device", USBPHY_OTGTUNE0_AX, false);
}
#endif
}
#endif
///////////////////////////////////////////////////////////
//
// USB Widgets Control
//
///////////////////////////////////////////////////////////
#if !AUSB_USB20PHY_ONLY_VERSION
void ausb_setup_widgets()
{
clock_gate(CLK_USB, true);
// USB_CTL clock should be enabled
rAUSB_WIDGET_OTG_ADDR = high_addr_bits;
rAUSB_WIDGET_OHCI0_ADDR = high_addr_bits;
// Only if EHCI is NOT capable of 64 bit addressing ...
#if (USBEHCI_ADDR_EXT_WIDGET_EN == 1)
rAUSB_WIDGET_EHCI0_ADDR = high_addr_bits;
rAUSB_WIDGET_EHCI1_ADDR = high_addr_bits;
#endif
clock_gate(CLK_USB, false);
}
#endif