blob: 307347a43bde20c0296a157eae9d35b1a059318b [file] [log] [blame]
/*
* Misc utility routines for accessing PMU corerev specific features
* of the SiliconBackplane-based Broadcom chips.
*
* Copyright (C) 1999-2010, Broadcom Corporation
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2 (the "GPL"),
* available at http://www.broadcom.com/licenses/GPLv2.php, with the
* following added to such license:
*
* As a special exception, the copyright holders of this software give you
* permission to link this software with independent modules, and to copy and
* distribute the resulting executable under terms of your choice, provided that
* you also meet, for each linked independent module, the terms and conditions of
* the license of that module. An independent module is a module which is not
* derived from this software. The special exception does not apply to any
* modifications of the software.
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a license
* other than the GPL, without Broadcom's express prior written consent.
*
* $Id: hndpmu.c,v 1.95.2.17.4.11.2.63 2010/07/21 13:55:09 Exp $
*/
#include <typedefs.h>
#include <bcmdefs.h>
#include <osl.h>
#include <bcmutils.h>
#include <siutils.h>
#include <bcmdevs.h>
#include <hndsoc.h>
#include <sbchipc.h>
#include <hndpmu.h>
/* debug/trace */
#define PMU_ERROR(args)
#define PMU_MSG(args)
/* SDIO Pad drive strength to select value mappings */
typedef struct {
uint8 strength; /* Pad Drive Strength in mA */
uint8 sel; /* Chip-specific select value */
} sdiod_drive_str_t;
/* SDIO Drive Strength to sel value table for PMU Rev 1 */
static const sdiod_drive_str_t sdiod_drive_strength_tab1[] = {
{4, 0x2},
{2, 0x3},
{1, 0x0},
{0, 0x0} };
/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
static const sdiod_drive_str_t sdiod_drive_strength_tab2[] = {
{12, 0x7},
{10, 0x6},
{8, 0x5},
{6, 0x4},
{4, 0x2},
{2, 0x1},
{0, 0x0} };
#define SDIOD_DRVSTR_KEY(chip, pmu) (((chip) << 16) | (pmu))
void
si_sdiod_drive_strength_init(si_t *sih, osl_t *osh, uint32 drivestrength)
{
chipcregs_t *cc;
uint origidx, intr_val = 0;
sdiod_drive_str_t *str_tab = NULL;
uint32 str_mask = 0;
uint32 str_shift = 0;
if (!(sih->cccaps & CC_CAP_PMU)) {
return;
}
/* Remember original core before switch to chipc */
cc = (chipcregs_t *) si_switch_core(sih, CC_CORE_ID, &origidx, &intr_val);
switch (SDIOD_DRVSTR_KEY(sih->chip, sih->pmurev)) {
case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab1;
str_mask = 0x30000000;
str_shift = 28;
break;
case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
case SDIOD_DRVSTR_KEY(BCM4315_CHIP_ID, 4):
str_tab = (sdiod_drive_str_t *)&sdiod_drive_strength_tab2;
str_mask = 0x00003800;
str_shift = 11;
break;
default:
PMU_MSG(("No SDIO Drive strength init done for chip %x rev %d pmurev %d\n",
sih->chip, sih->chiprev, sih->pmurev));
break;
}
if (str_tab != NULL) {
uint32 drivestrength_sel = 0;
uint32 cc_data_temp;
int i;
for (i = 0; str_tab[i].strength != 0; i ++) {
if (drivestrength >= str_tab[i].strength) {
drivestrength_sel = str_tab[i].sel;
break;
}
}
W_REG(osh, &cc->chipcontrol_addr, 1);
cc_data_temp = R_REG(osh, &cc->chipcontrol_data);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
W_REG(osh, &cc->chipcontrol_data, cc_data_temp);
PMU_MSG(("SDIO: %dmA drive strength selected, set to 0x%08x\n",
drivestrength, cc_data_temp));
}
/* Return to original core */
si_restore_core(sih, origidx, intr_val);
}