blob: f54b68597096ab42b0a4e0a3d2798883cc9c4a80 [file] [log] [blame]
/*
* Copyright (C) 2009 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdarg.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/sysfs.h>
#include <linux/device.h>
#include <linux/ctype.h>
#include <linux/smp.h>
#include <linux/platform_device.h>
#include <linux/suspend.h>
#include <linux/mii.h>
#include <linux/spinlock.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/compiler.h>
#include <linux/brcmstb/brcmstb.h>
/* Wakeup on timeout (20 sec) even if standby_flags does not request this */
#define WATCHDOG_TIMER_WAKEUP_ALWAYS (0)
#define PRINT_PM_CALLBACK printk(KERN_DEBUG "%s %02x\n", \
__func__, (u8)flags)
#if 0
#define DBG printk
#else
#define DBG(...) do { } while (0)
#endif
/***********************************************************************
* USB / ENET / GENET / MoCA / SATA PM common internal functions
***********************************************************************/
struct clk {
char name[16];
int refcnt;
struct clk *parent;
int (*cb)(int, void *);
void *cb_arg;
void (*disable)(u32 flags);
void (*enable)(u32 flags);
int (*set_rate)(unsigned long rate);
unsigned long rate;
u32 flags;
struct list_head list;
};
/*
* Flags:
* BRCM_PM_FLAG_S3 - S3 standby inititated. Since all blocks lose
* power, there is no need to preserve state.
* On-chip SRAM can be unconditionally powered down.
* BRCM_PM_FLAG_ENET_WOL - Ethernet WOL is a wake-up event
* BRCM_PM_FLAG_MOCA_WOL - MoCA WOL is a wake-up event
* BRCM_PM_FLAG_USB_WAKEUP - USB insertion/removal is a wake-up event
*/
#define BRCM_PM_FLAG_S3 0x01 /* set when suspend begins */
#define BRCM_PM_FLAG_ENET_WOL 0x02 /* ENET WOL is enabled */
#define BRCM_PM_FLAG_MOCA_WOL 0x04 /* MoCA WOL is enabled */
#define BRCM_PM_FLAG_USB_WAKEUP 0x08 /* USB insertion/removal wakeup */
#define ANY_WOL(flags) (flags & (BRCM_PM_FLAG_ENET_WOL|BRCM_PM_FLAG_MOCA_WOL))
#define ENET_WOL(flags) (flags & BRCM_PM_FLAG_ENET_WOL)
#define MOCA_WOL(flags) (flags & BRCM_PM_FLAG_MOCA_WOL)
static DEFINE_SPINLOCK(brcm_pm_clk_lock);
static void brcm_pm_sata_disable(u32 flags);
static void brcm_pm_sata_enable(u32 flags);
static void brcm_pm_genet_disable(u32 flags);
static void brcm_pm_genet_enable(u32 flags);
static void brcm_pm_genet_disable_wol(u32 flags);
static void brcm_pm_genet_enable_wol(u32 flags);
static void brcm_pm_moca_disable(u32 flags);
static void brcm_pm_moca_enable(u32 flags);
static void brcm_pm_moca_disable_wol(u32 flags);
static void brcm_pm_moca_enable_wol(u32 flags);
static void brcm_pm_genet1_disable(u32 flags);
static void brcm_pm_genet1_enable(u32 flags);
static void brcm_pm_network_disable(u32 flags);
static void brcm_pm_network_enable(u32 flags);
static void brcm_pm_usb_disable(u32 flags);
static void brcm_pm_usb_enable(u32 flags);
static void brcm_pm_set_ddr_timeout(int);
static void brcm_pm_initialize(void);
static int brcm_pm_moca_cpu_set_rate(unsigned long rate);
static int brcm_pm_moca_phy_set_rate(unsigned long rate);
static int brcm_pm_ddr_timeout;
static unsigned long brcm_pm_standby_flags;
static unsigned long brcm_pm_standby_timeout;
enum {
BRCM_CLK_SATA,
BRCM_CLK_GENET,
BRCM_CLK_MOCA,
BRCM_CLK_USB,
BRCM_CLK_GENET1,
BRCM_CLK_NETWORK, /* PLLs/clocks common to all GENETs */
BRCM_CLK_GENET_WOL,
BRCM_CLK_MOCA_WOL,
BRCM_CLK_MOCA_PHY,
BRCM_CLK_MOCA_CPU,
};
static struct clk brcm_clk_table[] = {
[BRCM_CLK_SATA] = {
.name = "sata",
.disable = &brcm_pm_sata_disable,
.enable = &brcm_pm_sata_enable,
},
[BRCM_CLK_GENET] = {
.name = "enet",
.disable = &brcm_pm_genet_disable,
.enable = &brcm_pm_genet_enable,
.parent = &brcm_clk_table[BRCM_CLK_NETWORK],
},
[BRCM_CLK_MOCA] = {
.name = "moca",
.disable = &brcm_pm_moca_disable,
.enable = &brcm_pm_moca_enable,
.parent = &brcm_clk_table[BRCM_CLK_GENET1],
},
[BRCM_CLK_USB] = {
.name = "usb",
.disable = &brcm_pm_usb_disable,
.enable = &brcm_pm_usb_enable,
},
[BRCM_CLK_GENET1] = {
.name = "moca_genet",
.disable = &brcm_pm_genet1_disable,
.enable = &brcm_pm_genet1_enable,
.parent = &brcm_clk_table[BRCM_CLK_NETWORK],
},
[BRCM_CLK_NETWORK] = {
.name = "network",
.disable = &brcm_pm_network_disable,
.enable = &brcm_pm_network_enable,
},
[BRCM_CLK_GENET_WOL] = {
.name = "enet-wol",
.disable = &brcm_pm_genet_disable_wol,
.enable = &brcm_pm_genet_enable_wol,
},
[BRCM_CLK_MOCA_WOL] = {
.name = "moca-wol",
.disable = &brcm_pm_moca_disable_wol,
.enable = &brcm_pm_moca_enable_wol,
},
[BRCM_CLK_MOCA_CPU] = {
.name = "moca-cpu",
.set_rate = &brcm_pm_moca_cpu_set_rate,
},
[BRCM_CLK_MOCA_PHY] = {
.name = "moca-phy",
.set_rate = &brcm_pm_moca_phy_set_rate,
},
};
/* These clocks are chip specific - each .initialize()
method will add them if needed */
static LIST_HEAD(brcm_dyn_clk_list);
static __maybe_unused void __clk_dyn_add(struct clk *clk)
{
struct clk *clk_p;
list_for_each_entry(clk_p, &brcm_dyn_clk_list, list) {
if (clk_p == clk)
return;
}
list_add(&clk->list, &brcm_dyn_clk_list);
}
static __maybe_unused void __clk_dyn_del(struct clk *clk)
{
list_del(&clk->list);
}
static struct clk *brcm_pm_clk_find(const char *name)
{
int i;
struct clk *clk = brcm_clk_table;
BUG_ON(!name);
/* first check static clocks */
for (i = 0; i < ARRAY_SIZE(brcm_clk_table); i++, clk++)
if (!strncmp(name, clk->name, strlen(name)))
return clk;
/* check dynamic clocks */
list_for_each_entry(clk, &brcm_dyn_clk_list, list) {
if (!strncmp(name, clk->name, strlen(name)))
return clk;
}
return NULL;
}
/* sysfs attributes */
ssize_t brcm_pm_show_sata_power(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct clk *clk = brcm_pm_clk_find("sata");
return snprintf(buf, PAGE_SIZE, "%d\n", !!clk->refcnt);
}
ssize_t brcm_pm_store_sata_power(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct clk *clk = brcm_pm_clk_find("sata");
int val;
if (!clk || !clk->cb || sscanf(buf, "%d", &val) != 1)
return -EINVAL;
return clk->cb(val ? PM_EVENT_RESUME : PM_EVENT_SUSPEND,
clk->cb_arg) ? : count;
}
ssize_t brcm_pm_show_ddr_timeout(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", brcm_pm_ddr_timeout);
}
ssize_t brcm_pm_store_ddr_timeout(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int val;
if (sscanf(buf, "%d", &val) != 1)
return -EINVAL;
brcm_pm_ddr_timeout = val;
if (brcm_pm_enabled)
brcm_pm_set_ddr_timeout(val);
return count;
}
ssize_t brcm_pm_show_standby_flags(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "0x%lx\n", brcm_pm_standby_flags);
}
ssize_t brcm_pm_store_standby_flags(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long val;
if (sscanf(buf, "%lx", &val) != 1)
return -EINVAL;
brcm_pm_standby_flags = val;
return count;
}
ssize_t brcm_pm_show_standby_timeout(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%lu\n", brcm_pm_standby_timeout);
}
ssize_t brcm_pm_store_standby_timeout(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned long val;
if (sscanf(buf, "%lu", &val) != 1)
return -EINVAL;
brcm_pm_standby_timeout = val;
return count;
}
#if defined(CONFIG_BRCM_HAS_1GB_MEMC1) || defined(CONFIG_BCM7420)
/*
* brcm_pm_memc1_power
* Power state of secondary memory controller
* 0 - complete power down (with loss of content)
* 1 - full power mode
* 2 - SSPD (content preserved)
* Direct transition between 0 and 2 is not supported
*/
#define BRCM_PM_MEMC1_OFF 0
#define BRCM_PM_MEMC1_ON 1
#define BRCM_PM_MEMC1_SSPD 2
static int brcm_pm_memc1_power = BRCM_PM_MEMC1_ON;
int __weak brcm_pm_memc1_suspend(void) { return 0; }
int __weak brcm_pm_memc1_resume(void) { return 0; }
int __weak brcm_pm_memc1_powerdown(void) { return 0; }
int __weak brcm_pm_memc1_powerup(void) { return 0; }
ssize_t brcm_pm_show_memc1_power(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", brcm_pm_memc1_power);
}
ssize_t brcm_pm_store_memc1_power(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int val;
/*
* if memc1 memory has been added to system memory pool,
* disable memc1 dynamic PM
*/
if (brcm_dram1_linux_mb && brcm_dram1_linux_mb <= brcm_dram1_size_mb) {
sysfs_chmod_file(&dev->kobj,
&attr->attr, attr->attr.mode & ~S_IWUGO);
return -EINVAL;
}
if (sscanf(buf, "%d", &val) != 1)
return -EINVAL;
/* check for no change */
if (val == brcm_pm_memc1_power)
return count;
switch (val) {
case BRCM_PM_MEMC1_OFF:
if (brcm_pm_memc1_power == BRCM_PM_MEMC1_ON)
brcm_pm_memc1_powerdown();
else
return -EINVAL;
break;
case BRCM_PM_MEMC1_ON:
if (brcm_pm_memc1_power == BRCM_PM_MEMC1_OFF) {
if (brcm_pm_memc1_powerup())
return -EINVAL;
} else if (brcm_pm_memc1_power == BRCM_PM_MEMC1_SSPD)
brcm_pm_memc1_resume();
else
return -EINVAL;
break;
case BRCM_PM_MEMC1_SSPD:
if (brcm_pm_memc1_power == BRCM_PM_MEMC1_ON)
brcm_pm_memc1_suspend();
else
return -EINVAL;
break;
default:
return -EINVAL;
}
brcm_pm_memc1_power = val;
return count;
}
#endif
static u32 brcm_pm_time_at_wakeup[2];
ssize_t brcm_pm_show_time_at_wakeup(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n",
brcm_pm_time_at_wakeup[0], brcm_pm_time_at_wakeup[1]);
}
static int brcm_pm_halt_mode;
ssize_t brcm_pm_show_halt_mode(struct device *dev,
struct device_attribute *attr, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%d\n", brcm_pm_halt_mode);
}
ssize_t brcm_pm_store_halt_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int val;
if (sscanf(buf, "%d", &val) != 1)
return -EINVAL;
brcm_pm_halt_mode = !!val;
return count;
}
/* Boot time functions */
static int __init brcm_pm_init(void)
{
if (!brcm_pm_enabled)
return 0;
if (!brcm_moca_enabled)
brcm_pm_moca_disable(0);
/* chip specific initialization */
brcm_pm_initialize();
return 0;
}
early_initcall(brcm_pm_init);
static int nopm_setup(char *str)
{
brcm_pm_enabled = 0;
return 0;
}
__setup("nopm", nopm_setup);
int brcm_pm_hash_enabled = 1;
static int nohash_setup(char *str)
{
brcm_pm_hash_enabled = 0;
return 0;
}
__setup("nohash", nohash_setup);
/***********************************************************************
* USB / ENET / GENET / MoCA / SATA PM external API
***********************************************************************/
/* internal functions assume the lock is held */
static int __clk_enable(struct clk *clk, u32 flags)
{
BUG_ON(clk->refcnt < 0);
if (++(clk->refcnt) == 1 && brcm_pm_enabled) {
if (clk->parent)
__clk_enable(clk->parent, clk->flags | flags);
printk(KERN_DEBUG "%s: %s [%d]\n",
__func__, clk->name, clk->refcnt);
if (clk->enable)
clk->enable(clk->flags | flags);
}
return 0;
}
static void __clk_disable(struct clk *clk, u32 flags)
{
if (--(clk->refcnt) == 0 && brcm_pm_enabled) {
printk(KERN_DEBUG "%s: %s [%d]\n",
__func__, clk->name, clk->refcnt);
if (clk->disable)
clk->disable(clk->flags | flags);
if (clk->parent)
__clk_disable(clk->parent, clk->flags | flags);
}
BUG_ON(clk->refcnt < 0);
}
int clk_enable(struct clk *clk)
{
unsigned long flags;
if (clk && !IS_ERR(clk)) {
spin_lock_irqsave(&brcm_pm_clk_lock, flags);
__clk_enable(clk, 0);
spin_unlock_irqrestore(&brcm_pm_clk_lock, flags);
return 0;
} else {
return -EINVAL;
}
}
EXPORT_SYMBOL(clk_enable);
void clk_disable(struct clk *clk)
{
unsigned long flags;
if (clk && !IS_ERR(clk)) {
spin_lock_irqsave(&brcm_pm_clk_lock, flags);
__clk_disable(clk, 0);
spin_unlock_irqrestore(&brcm_pm_clk_lock, flags);
}
}
EXPORT_SYMBOL(clk_disable);
void clk_put(struct clk *clk)
{
}
EXPORT_SYMBOL(clk_put);
int clk_set_parent(struct clk *clk, struct clk *parent)
{
unsigned long flags;
spinlock_t *lock = &brcm_pm_clk_lock;
if (clk && !IS_ERR(clk)) {
spin_lock_irqsave(lock, flags);
clk->parent = parent;
spin_unlock_irqrestore(lock, flags);
return 0;
}
return -EINVAL;
}
EXPORT_SYMBOL(clk_set_parent);
struct clk *clk_get_parent(struct clk *clk)
{
if (clk && !IS_ERR(clk))
return clk->parent;
return NULL;
}
EXPORT_SYMBOL(clk_get_parent);
unsigned long clk_get_rate(struct clk *clk)
{
return clk->rate;
}
EXPORT_SYMBOL(clk_get_rate);
int clk_set_rate(struct clk *clk, unsigned long rate)
{
unsigned long flags;
int ret;
spinlock_t *lock = &brcm_pm_clk_lock;
if (clk && !IS_ERR(clk) && clk->set_rate) {
spin_lock_irqsave(lock, flags);
ret = clk->set_rate(rate);
if (!ret) clk->rate = rate;
spin_unlock_irqrestore(lock, flags);
return ret;
}
return -EINVAL;
}
EXPORT_SYMBOL(clk_set_rate);
int brcm_pm_register_cb(char *name, int (*fn)(int, void *), void *arg)
{
struct clk *clk = brcm_pm_clk_find(name);
unsigned long flags;
if (!clk)
return -ENOENT;
spin_lock_irqsave(&brcm_pm_clk_lock, flags);
BUG_ON(fn && clk->cb);
clk->cb = fn;
clk->cb_arg = arg;
spin_unlock_irqrestore(&brcm_pm_clk_lock, flags);
return 0;
}
EXPORT_SYMBOL(brcm_pm_register_cb);
int brcm_pm_unregister_cb(char *name)
{
return brcm_pm_register_cb(name, NULL, NULL);
}
EXPORT_SYMBOL(brcm_pm_unregister_cb);
#ifdef CONFIG_BRCM_HAS_STANDBY
/***********************************************************************
* Wakeup source management
* All kernel drivers can use this api to register their wakeup
* sources. This will enable 'lightweight' resume feature, when
* wakeup event is quickly qualified immediately after resume using
* driver-supplied poll() method. If none of registered poll() method
* recognize the wakeup event, system may be brought back to sleep.
* To allow for other components to use their wakeup capabilities, system
* suspend code will save the pre-suspend PM_L2 mask and, if all poll()
* callbacks deny the wakeup event, check if one of events enabled in the
* saved mask has occurred.
***********************************************************************/
struct brcm_wakeup_source {
struct brcm_wakeup_ops *ops;
void *ref;
struct list_head list;
struct kref kref;
char name[16];
};
struct brcm_wakeup_control {
spinlock_t lock;
struct list_head head;
int count;
};
static struct brcm_wakeup_control bwc;
int brcm_pm_wakeup_register(struct brcm_wakeup_ops *ops, void *ref, char *name)
{
struct brcm_wakeup_source *bws;
unsigned long flags;
list_for_each_entry(bws, &bwc.head, list) {
if (bws->ops == ops && bws->ref == ref) {
/* already registered */
spin_lock_irqsave(&bwc.lock, flags);
kref_get(&bws->kref);
spin_unlock_irqrestore(&bwc.lock, flags);
return 0;
}
}
bws = kmalloc(sizeof(struct brcm_wakeup_source), GFP_ATOMIC);
if (!bws)
return -1;
bws->ops = ops;
bws->ref = ref;
if (name)
strncpy(bws->name, name, 16);
kref_init(&bws->kref);
kref_get(&bws->kref);
spin_lock_irqsave(&bwc.lock, flags);
list_add_tail(&bws->list, &bwc.head);
spin_unlock_irqrestore(&bwc.lock, flags);
return 0;
}
EXPORT_SYMBOL(brcm_pm_wakeup_register);
/* This function is called with bwc lock held*/
static void brcm_pm_wakeup_cleanup(struct kref *kref)
{
struct brcm_wakeup_source *bws =
container_of(kref, struct brcm_wakeup_source, kref);
list_del(&bws->list);
kfree(bws);
}
int brcm_pm_wakeup_unregister(struct brcm_wakeup_ops *ops, void *ref)
{
struct brcm_wakeup_source *bws;
unsigned long flags;
spin_lock_irqsave(&bwc.lock, flags);
list_for_each_entry(bws, &bwc.head, list)
if (bws->ops == ops && bws->ref == ref)
kref_put(&bws->kref, brcm_pm_wakeup_cleanup);
spin_unlock_irqrestore(&bwc.lock, flags);
return 0;
}
static int brcm_pm_wakeup_enable(void)
{
struct brcm_wakeup_source *bws;
unsigned long flags;
spin_lock_irqsave(&bwc.lock, flags);
list_for_each_entry(bws, &bwc.head, list) {
if (bws->ops && bws->ops->enable)
bws->ops->enable(bws->ref);
}
spin_unlock_irqrestore(&bwc.lock, flags);
return 0;
}
static int brcm_pm_wakeup_disable(void)
{
struct brcm_wakeup_source *bws;
unsigned long flags;
spin_lock_irqsave(&bwc.lock, flags);
list_for_each_entry(bws, &bwc.head, list) {
if (bws->ops && bws->ops->disable)
bws->ops->disable(bws->ref);
}
spin_unlock_irqrestore(&bwc.lock, flags);
return 0;
}
/*
Function asks all registered objects if a wakeup event has happened.
If no registered object claims the event, it checks for all interrupts
enabled prior to suspend.
It returns 0 if no valid wake up event has occurred, 1 otherwise.
*/
static int brcm_pm_wakeup_poll(u32 mask)
{
int ev_occurred = 0;
struct brcm_wakeup_source *bws;
unsigned long flags;
spin_lock_irqsave(&bwc.lock, flags);
list_for_each_entry(bws, &bwc.head, list) {
if (bws->ops && bws->ops->poll)
ev_occurred |= bws->ops->poll(bws->ref);
}
spin_unlock_irqrestore(&bwc.lock, flags);
/* Check for events outside of kernel control */
if (!ev_occurred)
ev_occurred |= brcm_pm_wakeup_get_status(~mask);
return ev_occurred;
}
int brcm_pm_wakeup_init(void)
{
spin_lock_init(&bwc.lock);
INIT_LIST_HEAD(&bwc.head);
return 0;
}
early_initcall(brcm_pm_wakeup_init);
#endif
/***********************************************************************
* USB / ENET / GENET / MoCA / SATA PM implementations (per-chip)
***********************************************************************/
static __maybe_unused void brcm_ddr_phy_initialize(void);
/*
* Per-block power management operations pair.
* Parameter flags is used to control wake-up capabilities
*/
struct brcm_chip_pm_block_ops {
void (*enable)(u32 flags);
void (*disable)(u32 flags);
int (*set_cpu_rate)(unsigned long rate);
int (*set_phy_rate)(unsigned long rate);
};
static u32 brcm_pm_flags;
struct brcm_chip_pm_ops {
/* SATA power/clock gating */
struct brcm_chip_pm_block_ops sata;
/* genet0 power/clock gating */
struct brcm_chip_pm_block_ops genet;
/* genet1 power/clock gating */
struct brcm_chip_pm_block_ops genet1;
/* MoCA power/clock gating */
struct brcm_chip_pm_block_ops moca;
/* USB power/clock gating */
struct brcm_chip_pm_block_ops usb;
/* genet0/genet1/MoCA common power/clock gating */
struct brcm_chip_pm_block_ops network;
/* system-wide initialization code */
void (*initialize)(void);
/* system suspend code */
void (*suspend)(u32 flags);
/* system resume code */
void (*resume)(u32 flags);
/*
* System suspend code executed immediately before
* initiating low-level suspend sequence.
* For example, shutting down secondary memory controller
* can be done here when system no longer uses highmem regions
*/
void (*late_suspend)(void);
void (*early_resume)(void);
/* for chip specific clock mappings ( see #SWLINUX-1764 ) */
struct clk* (*clk_get)(struct device *dev, const char *id);
};
#define DEF_BLOCK_PM_OP(block, chip) \
.block.enable = bcm##chip##_pm_##block##_enable, \
.block.disable = bcm##chip##_pm_##block##_disable
#define DEF_SYSTEM_PM_OP(chip) \
.suspend = bcm##chip##_pm_suspend, \
.resume = bcm##chip##_pm_resume
#define DEF_SYSTEM_LATE_PM_OP(chip) \
.late_suspend = bcm##chip##_pm_late_suspend, \
.early_resume = bcm##chip##_pm_early_resume
#define PLL_CH_DIS(x) BDEV_WR_RB(BCHP_##x, 0x04)
#define PLL_CH_ENA(x) do { \
BDEV_WR_RB(BCHP_##x, 0x03); \
mdelay(1); \
} while (0)
#define PLL_DIS(x) BDEV_WR_RB(BCHP_##x, 0x04)
#define PLL_ENA(x) do { \
BDEV_WR_RB(BCHP_##x, 0x03); \
mdelay(1); \
} while (0)
static __maybe_unused struct clk *brcm_pm_clk_get(struct device *dev,
const char *id)
{
if (id && !strncmp(id, "enet", 4) && dev) {
struct platform_device *pdev = to_platform_device(dev);
if (pdev->id == 0) /* enet */
return brcm_pm_clk_find(id);
if (pdev->id == 1) /* moca_genet */ {
if (strstr(id, "-wol"))
return brcm_pm_clk_find("moca-wol");
return brcm_pm_clk_find("moca");
}
}
return NULL;
}
/***********************************************************************
* Encryption setup for S3 suspend
***********************************************************************/
static struct brcm_dram_encoder_ops *dram_encoder_ops;
void brcm_pm_set_dram_encoder(struct brcm_dram_encoder_ops *ops)
{
dram_encoder_ops = ops;
}
EXPORT_SYMBOL(brcm_pm_set_dram_encoder);
#ifdef CONFIG_BRCM_HAS_AON
int brcm_pm_dram_encoder_prepare(struct brcm_mem_transfer *param)
{
if (dram_encoder_ops && dram_encoder_ops->prepare)
return dram_encoder_ops->prepare(param);
return -1;
}
EXPORT_SYMBOL(brcm_pm_dram_encoder_prepare);
int brcm_pm_dram_encoder_complete(struct brcm_mem_transfer *param)
{
if (dram_encoder_ops && dram_encoder_ops->complete)
return dram_encoder_ops->complete(param);
return -1;
}
EXPORT_SYMBOL(brcm_pm_dram_encoder_complete);
void brcm_pm_dram_encoder_start(void)
{
if (dram_encoder_ops && dram_encoder_ops->start)
dram_encoder_ops->start();
}
EXPORT_SYMBOL(brcm_pm_dram_encoder_start);
#endif /* CONFIG_BRCM_HAS_AON */
#if defined(CONFIG_BCM7125)
static void bcm7125_pm_sata_disable(u32 flags)
{
BDEV_WR_F_RB(SUN_TOP_CTRL_GENERAL_CTRL_1, sata_ana_pwrdn, 1);
BDEV_WR_F_RB(CLKGEN_SATA_CLK_PM_CTRL, DIS_CLK_99P7, 1);
BDEV_WR_F_RB(CLKGEN_SATA_CLK_PM_CTRL, DIS_CLK_216, 1);
BDEV_WR_F_RB(CLKGEN_SATA_CLK_PM_CTRL, DIS_CLK_108, 1);
PLL_CH_DIS(VCXO_CTL_MISC_RAP_AVD_PLL_CHL_4);
}
static void bcm7125_pm_sata_enable(u32 flags)
{
PLL_CH_ENA(VCXO_CTL_MISC_RAP_AVD_PLL_CHL_4);
BDEV_WR_F_RB(CLKGEN_SATA_CLK_PM_CTRL, DIS_CLK_108, 0);
BDEV_WR_F_RB(CLKGEN_SATA_CLK_PM_CTRL, DIS_CLK_216, 0);
BDEV_WR_F_RB(CLKGEN_SATA_CLK_PM_CTRL, DIS_CLK_99P7, 0);
BDEV_WR_F_RB(SUN_TOP_CTRL_GENERAL_CTRL_1, sata_ana_pwrdn, 0);
}
static void bcm7125_pm_network_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS,
CLOCK_SEL_ENET_CG_MOCA, 1);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS,
CLOCK_SEL_GMII_CG_MOCA, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_HFB, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_L2_INTR, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL,
DIS_CLK_UNIMAC_SYS_TX, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_216, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL,
DIS_CLK_250_GENET_MOCA, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_54, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_108, 1);
return;
}
BDEV_SET_RB(BCHP_CLKGEN_MOCA_CLK_PM_CTRL, 0xf77);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH3_PM_CTRL, 0x04);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH4_PM_CTRL, 0x04);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH5_PM_CTRL, 0x04);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH6_PM_CTRL, 0x04);
BDEV_SET_RB(BCHP_CLKGEN_PLL_MOCA_CTRL, 0x13);
}
static void bcm7125_pm_network_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS,
CLOCK_SEL_ENET_CG_MOCA, 0);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS,
CLOCK_SEL_GMII_CG_MOCA, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_L2_INTR, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL,
DIS_CLK_UNIMAC_SYS_TX, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_216, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL,
DIS_CLK_250_GENET_MOCA, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_54, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_CLK_PM_CTRL, DIS_CLK_108, 0);
return;
}
BDEV_UNSET_RB(BCHP_CLKGEN_PLL_MOCA_CTRL, 0x13);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH6_PM_CTRL, 0x01);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH5_PM_CTRL, 0x01);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH4_PM_CTRL, 0x01);
BDEV_WR_RB(BCHP_CLKGEN_PLL_MOCA_CH3_PM_CTRL, 0x01);
BDEV_UNSET_RB(BCHP_CLKGEN_MOCA_CLK_PM_CTRL, 0xf77);
}
static void bcm7125_pm_usb_disable(u32 flags)
{
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0x00);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_216, 1);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_108, 1);
PLL_CH_DIS(CLKGEN_PLL_MAIN_CH4_PM_CTRL);
}
static void bcm7125_pm_usb_enable(u32 flags)
{
PLL_CH_ENA(CLKGEN_PLL_MAIN_CH4_PM_CTRL);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_108, 0);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_216, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0x0f);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 1);
}
static void bcm7125_pm_suspend(u32 flags)
{
/* PCI/EBI */
BDEV_WR_RB(BCHP_HIF_TOP_CTRL_PM_CTRL, 0x3ff8);
BDEV_WR_F_RB(CLKGEN_CLK_27_OUT_PM_CTRL, DIS_CLK_27_OUT, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_PM_DIS_CHL_1, DIS_CH, 1);
BDEV_SET_RB(BCHP_CLKGEN_HIF_CLK_PM_CTRL, 0x3c);
/* system PLLs */
BDEV_SET_RB(BCHP_VCXO_CTL_MISC_VC0_CTRL, 0x0b);
BDEV_UNSET_RB(BCHP_VCXO_CTL_MISC_VC0_CTRL, 0x04);
BDEV_SET_RB(BCHP_VCXO_CTL_MISC_RAP_AVD_PLL_CTRL, 0x07);
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_216, 1);
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_108, 1);
/* disable self-refresh since it interferes with suspend */
brcm_pm_set_ddr_timeout(0);
}
static void bcm7125_pm_resume(u32 flags)
{
/* system PLLs */
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_108, 0);
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_216, 0);
BDEV_UNSET_RB(BCHP_VCXO_CTL_MISC_RAP_AVD_PLL_CTRL, 0x07);
BDEV_SET_RB(BCHP_VCXO_CTL_MISC_VC0_CTRL, 0x04);
BDEV_UNSET_RB(BCHP_VCXO_CTL_MISC_VC0_CTRL, 0x0b);
/* PCI/EBI */
BDEV_UNSET_RB(BCHP_CLKGEN_HIF_CLK_PM_CTRL, 0x3c);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_PM_DIS_CHL_1, DIS_CH, 0);
BDEV_WR_F_RB(CLKGEN_CLK_27_OUT_PM_CTRL, DIS_CLK_27_OUT, 0);
BDEV_WR_RB(BCHP_HIF_TOP_CTRL_PM_CTRL, 0x00);
brcm_ddr_phy_initialize();
}
/* There is no non-MoCA GENET on 7125, so any request for 'enet' clock is
* redirected to 'moca'
*/
static struct clk *bcm7125_pm_clk_get(struct device *dev, const char *id)
{
if (!strncmp(id, "enet", 4)) {
if (strstr(id, "-wol"))
return brcm_pm_clk_find("moca-wol");
else
return brcm_pm_clk_find("moca");
}
return NULL;
}
#define PM_OPS_DEFINED
static struct brcm_chip_pm_ops chip_pm_ops = {
DEF_BLOCK_PM_OP(usb, 7125),
DEF_BLOCK_PM_OP(sata, 7125),
DEF_BLOCK_PM_OP(network, 7125),
DEF_SYSTEM_PM_OP(7125),
.clk_get = bcm7125_pm_clk_get,
.initialize = brcm_ddr_phy_initialize,
};
#endif
#if defined(CONFIG_BCM7340)
static void bcm7340_pm_genet_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
/*
* TODO: Stop HFB clock and switch to 27MHz if ACPI
* detector is disabled
*/
#if 0
/* TODO: on 1000Mbit link use 54MHz clock and MAIN PLL */
BDEV_WR_F_RB(CLKGEN_PM_PLL_ALIVE_SEL, MAIN_PLL, 1);
mdelay(1);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS,
CLOCK_SEL_CG_GENET, 1);
#endif
/* switch to slower 27MHz clocks */
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS,
CLOCK_SEL_CG_GENET, 0);
BDEV_SET_RB(BCHP_CLKGEN_GENET_CLK_PM_CTRL,
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_216_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK);
return;
}
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH4_PM_CTRL, PWRDN_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH4_PM_CTRL, ENB_CLOCKOUT_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH4_PM_CTRL, EN_CMLBUF_CH4, 0);
BDEV_SET_RB(BCHP_CLKGEN_GENET_CLK_PM_CTRL,
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_250_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_RX_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_HFB_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_25_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_54_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_108_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_216_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_27X_PM_MASK);
}
static void bcm7340_pm_genet_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
BDEV_UNSET_RB(BCHP_CLKGEN_GENET_CLK_PM_CTRL,
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_HFB_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_216_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK);
/* switch to faster 54MHz clocks */
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_CG_GENET, 1);
return;
}
BDEV_UNSET_RB(BCHP_CLKGEN_GENET_CLK_PM_CTRL,
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_250_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_RX_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_HFB_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_25_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_54_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_108_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_216_MASK|
BCHP_CLKGEN_GENET_CLK_PM_CTRL_DIS_CLK_27X_PM_MASK);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH4_PM_CTRL, EN_CMLBUF_CH4, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH4_PM_CTRL, ENB_CLOCKOUT_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH4_PM_CTRL, PWRDN_CH, 0);
}
static void bcm7340_pm_moca_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (MOCA_WOL(flags)) {
#if 0
/* TODO: on 1000Mbit link use 54MHz clock and MAIN PLL */
BDEV_WR_F_RB(CLKGEN_PM_PLL_ALIVE_SEL, MAIN_PLL, 1);
mdelay(1);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_ENET_CG_MOCA,
1);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_GMII_CG_MOCA,
0);
#endif
/* switch to slower 27MHz clocks */
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_ENET_CG_MOCA,
0);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_GMII_CG_MOCA,
1);
BDEV_SET_RB(BCHP_CLKGEN_MOCA_CLK_PM_CTRL,
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_250_GENET_RGMII_MOCA_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_GENET_RGMII_CG_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_54_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_108_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_MASK);
return;
}
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH1_PM_CTRL, PWRDN_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH1_PM_CTRL, ENB_CLOCKOUT_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH1_PM_CTRL, EN_CMLBUF_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH2_PM_CTRL, PWRDN_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH2_PM_CTRL, ENB_CLOCKOUT_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH2_PM_CTRL, EN_CMLBUF_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH3_PM_CTRL, PWRDN_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH3_PM_CTRL, ENB_CLOCKOUT_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH3_PM_CTRL, EN_CMLBUF_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH6_PM_CTRL, PWRDN_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH6_PM_CTRL, ENB_CLOCKOUT_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH6_PM_CTRL, EN_CMLBUF_CH6, 0);
BDEV_SET_RB(BCHP_CLKGEN_MOCA_CLK_PM_CTRL,
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_250_GENET_RGMII_MOCA_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_GENET_RGMII_CG_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_RX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_HFB_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_27X_PM_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_54_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_108_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_MASK);
}
static void bcm7340_pm_moca_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (MOCA_WOL(flags)) {
BDEV_UNSET_RB(BCHP_CLKGEN_MOCA_CLK_PM_CTRL,
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_250_GENET_RGMII_MOCA_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_GENET_RGMII_CG_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_RX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_HFB_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_27X_PM_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_54_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_108_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_MASK);
/* Restore fast clocks */
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_ENET_CG_MOCA, 1);
BDEV_WR_F_RB(CLKGEN_MISC_CLOCK_SELECTS, CLOCK_SEL_GMII_CG_MOCA, 0);
return;
}
BDEV_UNSET_RB(BCHP_CLKGEN_MOCA_CLK_PM_CTRL,
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_250_GENET_RGMII_MOCA_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_GENET_RGMII_CG_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_RX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_UNIMAC_SYS_TX_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_L2_INTR_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_HFB_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_GMII_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_27X_PM_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_54_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_108_MASK|
BCHP_CLKGEN_MOCA_CLK_PM_CTRL_DIS_CLK_216_MASK);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH6_PM_CTRL, EN_CMLBUF_CH6, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH6_PM_CTRL, ENB_CLOCKOUT_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH6_PM_CTRL, PWRDN_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH3_PM_CTRL, EN_CMLBUF_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH3_PM_CTRL, ENB_CLOCKOUT_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH3_PM_CTRL, PWRDN_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH2_PM_CTRL, EN_CMLBUF_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH2_PM_CTRL, ENB_CLOCKOUT_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH2_PM_CTRL, PWRDN_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH1_PM_CTRL, EN_CMLBUF_CH, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH1_PM_CTRL, ENB_CLOCKOUT_CH, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CH1_PM_CTRL, PWRDN_CH, 0);
}
static void bcm7340_pm_usb_disable(u32 flags)
{
/* reset and power down all 4 ports */
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0x0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_SOFT_RESETB, 0x0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 0);
/* disable the clocks */
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_216, 1);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_108, 1);
/* disable PLL */
BDEV_WR_F_RB(CLKGEN_PLLMAIN_CH4_PM_CTRL, PWRDN_CH4_PLLMAIN, 1);
}
static void bcm7340_pm_usb_enable(u32 flags)
{
BDEV_WR_F_RB(CLKGEN_PLLMAIN_CH4_PM_CTRL, PWRDN_CH4_PLLMAIN, 0);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_108, 0);
BDEV_WR_F_RB(CLKGEN_USB_CLK_PM_CTRL, DIS_CLK_216, 0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_SOFT_RESETB, 0xF);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0xF);
}
static void bcm7340_pm_network_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ANY_WOL(flags))
return;
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, DRESET, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, ARESET, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, PWRDN, 1);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, PWRDN_LDO, 1);
}
static void bcm7340_pm_network_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ANY_WOL(flags))
return;
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, PWRDN_LDO, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, PWRDN, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, ARESET, 0);
BDEV_WR_F_RB(CLKGEN_PLLMOCA_CTRL, DRESET, 0);
}
static void bcm7340_pm_suspend(u32 flags)
{
PRINT_PM_CALLBACK;
/* PCI/EBI */
BDEV_WR_F_RB(CLKGEN_PAD_CLK_PM_CTRL, DIS_CLK_33_27_PCI, 1);
BDEV_WR_F_RB(CLKGEN_PLLMAIN_CH5_PM_CTRL, PWRDN_CH5_PLLMAIN, 1);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_81, 1);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_27, 1);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_54, 1);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_216_CG, 1);
BDEV_WR_F_RB(CLKGEN_HIF_CLK_PM_CTRL, DIS_CLK_SPI, 1);
/* system PLLs */
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, DRESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, ARESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, POWERDOWN, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC1_CTRL, DRESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC1_CTRL, ARESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC1_CTRL, POWERDOWN, 1);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_PM_CH2_CTRL, EN_CMLBUF, 0);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_PM_CH2_CTRL, PWRDN, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_RAP_AVD_PLL_CTRL, RESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_RAP_AVD_PLL_CTRL, POWERDOWN, 1);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, ENB_CLOCKOUT, 1);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, DRESET, 1);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, ARESET, 1);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, PWRDN, 1);
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_216, 1);
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_108, 1);
/* disable self-refresh since it interferes with suspend */
brcm_pm_set_ddr_timeout(0);
}
static void bcm7340_pm_resume(u32 flags)
{
PRINT_PM_CALLBACK;
/* system PLLs */
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_108, 0);
BDEV_WR_F_RB(CLKGEN_VCXO_CLK_PM_CTRL, DIS_CLK_216, 0);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, PWRDN, 0);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, ARESET, 0);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, DRESET, 0);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_CTRL, ENB_CLOCKOUT, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_RAP_AVD_PLL_CTRL, RESET, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_RAP_AVD_PLL_CTRL, POWERDOWN, 0);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_PM_CH2_CTRL, PWRDN, 1);
BDEV_WR_F_RB(CLKGEN_PLLAVD_RDSP_PM_CH2_CTRL, EN_CMLBUF, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC1_CTRL, POWERDOWN, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC1_CTRL, ARESET, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC1_CTRL, DRESET, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, POWERDOWN, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, ARESET, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, DRESET, 0);
/* PCI/EBI */
BDEV_WR_F_RB(CLKGEN_HIF_CLK_PM_CTRL, DIS_CLK_SPI, 0);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_216_CG, 0);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_54, 0);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_27, 0);
BDEV_WR_F_RB(CLKGEN_CG_CLK_PM_CTRL, DIS_CLK_81, 0);
BDEV_WR_F_RB(CLKGEN_PLLMAIN_CH5_PM_CTRL, PWRDN_CH5_PLLMAIN, 0);
BDEV_WR_F_RB(CLKGEN_PAD_CLK_PM_CTRL, DIS_CLK_33_27_PCI, 0);
brcm_ddr_phy_initialize();
}
#define PM_OPS_DEFINED
static struct brcm_chip_pm_ops chip_pm_ops = {
DEF_BLOCK_PM_OP(usb, 7340),
DEF_BLOCK_PM_OP(moca, 7340),
DEF_BLOCK_PM_OP(genet, 7340),
DEF_BLOCK_PM_OP(network, 7340),
DEF_SYSTEM_PM_OP(7340),
.clk_get = brcm_pm_clk_get,
.initialize = brcm_ddr_phy_initialize,
};
#endif
#if defined(CONFIG_BCM7408)
static void bcm7408_pm_network_disable(u32 flags)
{
PRINT_PM_CALLBACK;
/*
* 7408B0 does not support MoCA WOL due to a h/w bug. The
* following code is added in case the bug is fixed in the next
* revision
* http://jira.broadcom.com/browse/HW7408-186
*/
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_CLK_SEL, 1);
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_GMII_TX_CLK_SEL, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_GENET_RGMII_216M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_UNIMAC_SYS_TX_27_108M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_L2_INTR_27_108M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_GMII_TX_27_108M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_MOCA_54M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_216M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_108M_CLK, 1);
return;
}
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_MOCA_ENET_HFB_27_108M_CLK, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_3, DIS_CH, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_3, EN_CMLBUF, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_4, DIS_CH, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_4, EN_CMLBUF, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_5, DIS_CH, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_5, EN_CMLBUF, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_6, DIS_CH, 1);
BDEV_SET_RB(BCHP_CLK_MOCA_CLK_PM_CTRL, 0x6ab);
}
static void bcm7408_pm_network_enable(u32 flags)
{
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_GENET_RGMII_216M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_UNIMAC_SYS_TX_27_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_L2_INTR_27_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_GMII_TX_27_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_MOCA_54M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_216M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_CLK_SEL, 0);
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_GMII_TX_CLK_SEL, 0);
return;
}
BDEV_UNSET_RB(BCHP_CLK_MOCA_CLK_PM_CTRL, 0x6ab);
BDEV_WR_F_RB(CLK_SYS_PLL_1_6, DIS_CH, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_5, DIS_CH, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_5, EN_CMLBUF, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_4, DIS_CH, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_4, EN_CMLBUF, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_3, DIS_CH, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_3, EN_CMLBUF, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_MOCA_ENET_HFB_27_108M_CLK, 0);
}
static void bcm7408_pm_usb_disable(u32 flags)
{
/* reset and power down all 4 ports */
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0x0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_SOFT_RESETB, 0x0);
/* disable the clocks */
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 0);
BDEV_SET_RB(BCHP_CLK_USB_CLK_PM_CTRL,
BCHP_CLK_USB_CLK_PM_CTRL_DIS_54M_CLK_MASK|
BCHP_CLK_USB_CLK_PM_CTRL_DIS_108M_CLK_MASK|
BCHP_CLK_USB_CLK_PM_CTRL_DIS_216M_CLK_MASK);
/* disable PLL */
BDEV_WR_F_RB(CLK_SYS_PLL_0_4, DIS_CH, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_0_4, EN_CMLBUF, 0);
}
static void bcm7408_pm_usb_enable(u32 flags)
{
/* enable PLL */
BDEV_WR_F_RB(CLK_SYS_PLL_0_4, EN_CMLBUF, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_0_4, DIS_CH, 0);
/* enable the clocks */
BDEV_UNSET_RB(BCHP_CLK_USB_CLK_PM_CTRL,
BCHP_CLK_USB_CLK_PM_CTRL_DIS_54M_CLK_MASK|
BCHP_CLK_USB_CLK_PM_CTRL_DIS_108M_CLK_MASK|
BCHP_CLK_USB_CLK_PM_CTRL_DIS_216M_CLK_MASK);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_SOFT_RESETB, 0xE);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 0);
/* power up all 4 ports */
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0xF);
}
static void bcm7408_pm_suspend(u32 flags)
{
/* UART */
if (!(brcm_pm_standby_flags & BRCM_STANDBY_VERBOSE)) {
BDEV_WR_F_RB(CLK_SUN_27M_CLK_PM_CTRL,
DIS_SUN_27M_CLK, 1);
BDEV_WR_F_RB(CLK_SUN_UART_CLK_PM_CTRL,
DIS_SUN_UART_108M_CLK, 1);
}
/* PAD clocks */
BDEV_WR_F_RB(CLK_MISC, VCXOA_OUTCLK_ENABLE, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_PM_DIS_CHL_1, DIS_CH, 1);
/* system PLLs */
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, DRESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, ARESET, 1);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, POWERDOWN, 1);
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1,
CML_2_N_P_EN, 1);
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1,
FREQ_DOUBLER_POWER_DOWN, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, DRESET, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, ARESET, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, POWERDOWN, 1);
/* MEMC0 */
BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_DDR_PAD_CNTRL,
IDDQ_MODE_ON_SELFREF, 0);
BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_DDR_PAD_CNTRL,
HIZ_ON_SELFREF, 1);
BDEV_WR_F_RB(MEMC_DDR23_SHIM_ADDR_CNTL_DDR_PAD_CNTRL,
DEVCLK_OFF_ON_SELFREF, 1);
BDEV_WR_RB(BCHP_DDR23_PHY_CONTROL_REGS_0_IDLE_PAD_CONTROL, 0x132);
BDEV_SET_RB(BCHP_DDR23_PHY_BYTE_LANE_0_0_IDLE_PAD_CONTROL, 0xfffff);
BDEV_SET_RB(BCHP_DDR23_PHY_BYTE_LANE_1_0_IDLE_PAD_CONTROL, 0xfffff);
}
static void bcm7408_pm_resume(u32 flags)
{
/* system PLLs */
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, DRESET, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, ARESET, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, POWERDOWN, 0);
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1,
CML_2_N_P_EN, 0);
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1,
FREQ_DOUBLER_POWER_DOWN, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, DRESET, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, ARESET, 0);
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_CTRL, POWERDOWN, 0);
/* PAD clocks */
BDEV_WR_F_RB(VCXO_CTL_MISC_VC0_PM_DIS_CHL_1, DIS_CH, 0);
BDEV_WR_F_RB(CLK_MISC, VCXOA_OUTCLK_ENABLE, 1);
/* UART */
if (!(brcm_pm_standby_flags & BRCM_STANDBY_VERBOSE)) {
BDEV_WR_F_RB(CLK_SUN_UART_CLK_PM_CTRL,
DIS_SUN_UART_108M_CLK, 0);
BDEV_WR_F_RB(CLK_SUN_27M_CLK_PM_CTRL,
DIS_SUN_27M_CLK, 0);
}
}
#define PM_OPS_DEFINED
static struct brcm_chip_pm_ops chip_pm_ops = {
DEF_BLOCK_PM_OP(network, 7408),
DEF_BLOCK_PM_OP(usb, 7408),
DEF_SYSTEM_PM_OP(7408),
};
#endif
#if defined(CONFIG_BCM7420)
static void bcm7420_pm_usb_disable(u32 flags)
{
/* power down ports */
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_PWDNB, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI1_PWDNB, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY1_PWDNB, 0);
/* power down USB PLL */
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 0);
/* disable the clocks */
BDEV_SET_RB(BCHP_CLK_USB_PM_CTRL,
BCHP_CLK_USB_PM_CTRL_DIS_108M_CLK_MASK|
BCHP_CLK_USB_PM_CTRL_DIS_216M_CLK_MASK);
/* power down system PLL */
BDEV_WR_F_RB(CLK_SYS_PLL_0_PLL_4, DIS_CH, 1);
}
static void bcm7420_pm_usb_enable(u32 flags)
{
/* power up system PLL */
BDEV_WR_F_RB(CLK_SYS_PLL_0_PLL_4, DIS_CH, 0);
/* enable the clocks */
BDEV_UNSET_RB(BCHP_CLK_USB_PM_CTRL,
BCHP_CLK_USB_PM_CTRL_DIS_108M_CLK_MASK|
BCHP_CLK_USB_PM_CTRL_DIS_216M_CLK_MASK);
/* power up PLL */
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 1);
/* power up ports */
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_PWDNB, 3);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 3);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI1_PWDNB, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY1_PWDNB, 1);
}
static void bcm7420_pm_sata_disable(u32 flags)
{
BDEV_WR_F_RB(SUN_TOP_CTRL_GENERAL_CTRL_1, sata_ana_pwrdn, 1);
BDEV_WR_F_RB(CLK_SATA_CLK_PM_CTRL, DIS_SATA_PCI_CLK, 1);
BDEV_WR_F_RB(CLK_SATA_CLK_PM_CTRL, DIS_108M_CLK, 1);
BDEV_WR_F_RB(CLK_SATA_CLK_PM_CTRL, DIS_216M_CLK, 1);
PLL_CH_DIS(CLK_GENET_NETWORK_PLL_4);
}
static void bcm7420_pm_sata_enable(u32 flags)
{
PLL_CH_ENA(CLK_GENET_NETWORK_PLL_4);
BDEV_WR_F_RB(CLK_SATA_CLK_PM_CTRL, DIS_216M_CLK, 0);
BDEV_WR_F_RB(CLK_SATA_CLK_PM_CTRL, DIS_108M_CLK, 0);
BDEV_WR_F_RB(CLK_SATA_CLK_PM_CTRL, DIS_SATA_PCI_CLK, 0);
BDEV_WR_F_RB(SUN_TOP_CTRL_GENERAL_CTRL_1, sata_ana_pwrdn, 0);
}
static void bcm7420_pm_moca_disable(u32 flags)
{
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_CLK_SEL, 1);
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_GMII_TX_CLK_SEL, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_L2_INTR_27_108M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_UNIMAC_SYS_TX_27_108M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_216M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_MOCA_54M_CLK, 1);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_108M_CLK, 1);
return;
}
PLL_CH_DIS(CLK_SYS_PLL_1_3);
PLL_CH_DIS(CLK_SYS_PLL_1_4);
PLL_CH_DIS(CLK_SYS_PLL_1_5);
PLL_CH_DIS(CLK_SYS_PLL_1_6);
BDEV_SET_RB(BCHP_CLK_MOCA_CLK_PM_CTRL, 0x7bf);
}
static void bcm7420_pm_moca_enable(u32 flags)
{
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_L2_INTR_27_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL,
DIS_MOCA_ENET_UNIMAC_SYS_TX_27_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_216M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_MOCA_54M_CLK, 0);
BDEV_WR_F_RB(CLK_MOCA_CLK_PM_CTRL, DIS_108M_CLK, 0);
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_CLK_SEL, 0);
BDEV_WR_F_RB(CLK_MISC, MOCA_ENET_GMII_TX_CLK_SEL, 0);
return;
}
BDEV_UNSET_RB(BCHP_CLK_MOCA_CLK_PM_CTRL, 0x7bf);
PLL_CH_ENA(CLK_SYS_PLL_1_6);
PLL_CH_ENA(CLK_SYS_PLL_1_5);
PLL_CH_ENA(CLK_SYS_PLL_1_4);
PLL_CH_ENA(CLK_SYS_PLL_1_3);
}
static void bcm7420_pm_genet_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
BDEV_WR_F_RB(CLK_MISC, GENET_CLK_SEL, 1);
BDEV_WR_F_RB(CLK_MISC, GENET_GMII_TX_CLK_SEL, 1);
PLL_CH_DIS(CLK_GENET_NETWORK_PLL_5);
BDEV_SET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x143);
return;
}
PLL_CH_DIS(CLK_GENET_NETWORK_PLL_3);
PLL_CH_DIS(CLK_GENET_NETWORK_PLL_5);
PLL_CH_DIS(CLK_GENET_NETWORK_PLL_6);
BDEV_SET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x77F);
}
static void bcm7420_pm_genet_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
BDEV_UNSET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x143);
PLL_CH_ENA(CLK_GENET_NETWORK_PLL_5);
BDEV_WR_F_RB(CLK_MISC, GENET_CLK_SEL, 0);
BDEV_WR_F_RB(CLK_MISC, GENET_GMII_TX_CLK_SEL, 0);
return;
}
BDEV_UNSET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x77F);
PLL_CH_ENA(CLK_GENET_NETWORK_PLL_3);
PLL_CH_ENA(CLK_GENET_NETWORK_PLL_5);
PLL_CH_ENA(CLK_GENET_NETWORK_PLL_6);
}
static void bcm7420_pm_network_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ANY_WOL(flags))
return;
/* TODO - this clock is shared with HDMI */
PLL_CH_DIS(CLK_GENET_NETWORK_PLL_1);
BDEV_WR_F_RB(CLK_GENET_NETWORK_PLL_CTRL, POWERDOWN, 1);
BDEV_WR_F_RB(CLK_GENET_NETWORK_PLL_CTRL, RESET, 1);
}
static void bcm7420_pm_network_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ANY_WOL(flags))
return;
BDEV_WR_F_RB(CLK_GENET_NETWORK_PLL_CTRL, RESET, 0);
BDEV_WR_F_RB(CLK_GENET_NETWORK_PLL_CTRL, POWERDOWN, 0);
PLL_CH_ENA(CLK_GENET_NETWORK_PLL_1);
}
static void bcm7420_pm_suspend(u32 flags)
{
/* BT */
PLL_CH_DIS(CLK_SYS_PLL_1_1);
BDEV_SET_RB(BCHP_CLK_BLUETOOTH_CLK_PM_CTRL, 1);
if (!MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, POWERDOWN, 1);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, RESET, 1);
}
/* PCI/EBI */
BDEV_WR_RB(BCHP_HIF_TOP_CTRL_PM_CTRL, 0x3fff);
BDEV_WR_RB(BCHP_CLK_PCI_OUT_CLK_PM_CTRL, 0x1);
BDEV_WR_RB(BCHP_CLK_SYS_PLL_0_PLL_5, 0x2);
/* system PLLs */
if (!ANY_WOL(flags)) {
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1,
FREQ_DOUBLER_POWER_DOWN, 0);
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1, CML_2_N_P_EN, 1);
BDEV_WR_F_RB(CLK_SCRATCH, CML_REPEATER_2_POWERDOWN, 1);
}
BDEV_WR_RB(BCHP_CLK_SYS_PLL_0_PLL_6, 0x2);
/* disable self-refresh since it interferes with suspend */
brcm_pm_set_ddr_timeout(0);
BDEV_WR_F_RB(MEMC_DDR23_APHY_WL0_0_WORDSLICE_CNTRL_1,
PWRDN_DLL_ON_SELFREF,
!(brcm_pm_standby_flags & BRCM_STANDBY_DDR_PLL_ON));
BDEV_WR_F_RB(MEMC_DDR23_APHY_WL1_0_WORDSLICE_CNTRL_1,
PWRDN_DLL_ON_SELFREF,
!(brcm_pm_standby_flags & BRCM_STANDBY_DDR_PLL_ON));
}
static void bcm7420_pm_resume(u32 flags)
{
brcm_ddr_phy_initialize();
/* system PLLs */
BDEV_WR_F_RB(CLK_SCRATCH, CML_REPEATER_2_POWERDOWN, 0);
BDEV_WR_RB(BCHP_CLK_SYS_PLL_0_PLL_6, 0x1);
if (!ANY_WOL(flags)) {
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1, CML_2_N_P_EN, 0);
BDEV_WR_F_RB(CLK_THIRD_OT_CONTROL_1,
FREQ_DOUBLER_POWER_DOWN, 1);
}
/* Sundry */
BDEV_WR_F(CLK_SUN_27M_CLK_PM_CTRL, DIS_SUN_27M_CLK, 0);
/* PCI/EBI */
BDEV_WR_RB(BCHP_CLK_SYS_PLL_0_PLL_5, 0x1);
BDEV_WR_RB(BCHP_CLK_PCI_OUT_CLK_PM_CTRL, 0x0);
BDEV_WR_RB(BCHP_HIF_TOP_CTRL_PM_CTRL, 0x0);
if (!MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, RESET, 0);
BDEV_WR_F_RB(CLK_SYS_PLL_1_CTRL, POWERDOWN, 0);
}
/* BT */
BDEV_UNSET_RB(BCHP_CLK_BLUETOOTH_CLK_PM_CTRL, 1);
PLL_CH_ENA(CLK_SYS_PLL_1_1);
}
static void bcm7420_pm_late_suspend(void)
{
/* if MEMC1 is powered down/suspended, do not touch it */
if (brcm_pm_memc1_power == BRCM_PM_MEMC1_ON) {
brcm_pm_memc1_suspend();
brcm_pm_memc1_power = BRCM_PM_MEMC1_SSPD;
}
}
static void bcm7420_pm_early_resume(void)
{
/* if MEMC1 was powered down before standby, do not power it up */
if (brcm_pm_memc1_power == BRCM_PM_MEMC1_SSPD) {
brcm_pm_memc1_resume();
brcm_pm_memc1_power = BRCM_PM_MEMC1_ON;
}
}
static void bcm7420_pm_pcie_disable(u32 flags)
{
PRINT_PM_CALLBACK;
BDEV_WR_F_RB(HIF_RGR1_SW_RESET_1, PCIE_SW_PERST, 1);
PLL_CH_DIS(CLK_SYS_PLL_1_2);
BDEV_SET_RB(BCHP_CLK_PCIE_CLK_PM_CTRL, 1);
}
static void bcm7420_pm_pcie_enable(u32 flags)
{
PRINT_PM_CALLBACK;
BDEV_UNSET_RB(BCHP_CLK_PCIE_CLK_PM_CTRL, 1);
PLL_CH_ENA(CLK_SYS_PLL_1_2);
BDEV_WR_F_RB(HIF_RGR1_SW_RESET_1, PCIE_SW_PERST, 0);
}
static struct clk clk_pcie = {
.name = "pcie",
.disable = &bcm7420_pm_pcie_disable,
.enable = &bcm7420_pm_pcie_enable,
.refcnt = 1, /* enabled on boot */
};
static void bcm7420_initialize(void)
{
struct clk *nclk, *sclk;
brcm_ddr_phy_initialize();
/* extra clock dependency. See #SWLINUX-1913 */
nclk = clk_get(NULL, "network");
sclk = clk_get(NULL, "sata");
if (nclk && sclk)
clk_set_parent(sclk, nclk);
__clk_dyn_add(&clk_pcie);
}
#define PM_OPS_DEFINED
static struct brcm_chip_pm_ops chip_pm_ops = {
DEF_BLOCK_PM_OP(sata, 7420),
DEF_BLOCK_PM_OP(usb, 7420),
DEF_BLOCK_PM_OP(moca, 7420),
DEF_BLOCK_PM_OP(genet, 7420),
DEF_BLOCK_PM_OP(network, 7420),
DEF_SYSTEM_PM_OP(7420),
DEF_SYSTEM_LATE_PM_OP(7420),
.clk_get = brcm_pm_clk_get,
.initialize = bcm7420_initialize,
};
#endif
#if defined(CONFIG_BCM7468)
static void bcm7468_pm_genet_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
/* switch to slower 27MHz clocks */
BDEV_WR_F_RB(CLK_MISC, GENET_CLK_SEL, 1);
BDEV_WR_F_RB(CLK_MISC, GENET_GMII_TX_CLK_SEL, 1);
BDEV_SET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x503);
return;
}
BDEV_WR_RB(BCHP_CLK_SYS_PLL_1_4, 1);
BDEV_SET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x767);
}
static void bcm7468_pm_genet_enable(u32 flags)
{
if (ENET_WOL(flags)) {
BDEV_UNSET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x503);
BDEV_WR_F_RB(CLK_MISC, GENET_CLK_SEL, 0);
BDEV_WR_F_RB(CLK_MISC, GENET_GMII_TX_CLK_SEL, 0);
return;
}
BDEV_UNSET_RB(BCHP_CLK_GENET_CLK_PM_CTRL, 0x767);
BDEV_WR_RB(BCHP_CLK_SYS_PLL_1_4, 0);
}
static void bcm7468_pm_usb_disable(u32 flags)
{
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0x00);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_SOFT_RESETB, 0x00);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 0);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 0);
BDEV_SET_RB(BCHP_CLK_USB_CLK_PM_CTRL, 0x07);
}
static void bcm7468_pm_usb_enable(u32 flags)
{
BDEV_UNSET_RB(BCHP_CLK_USB_CLK_PM_CTRL, 0x07);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, XTAL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_PLL_CTL_1, PLL_PWRDWNB, 1);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_SOFT_RESETB, 0xF);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, UTMI_IDDQ, 0);
BDEV_WR_F_RB(USB_CTRL_UTMI_CTL_1, PHY_PWDNB, 0xF);
}
static void bcm7468_pm_suspend(u32 flags)
{
/* SDIO */
BDEV_WR_F_RB(CLK_HIF_SDIO_CLK_PM_CTRL, DIS_HIF_SDIO_48M_CLK, 1);
BDEV_WR_RB(BCHP_CLK_SYS_PLL_1_1, 1);
/* EBI */
BDEV_SET_RB(BCHP_HIF_TOP_CTRL_PM_CTRL, 0x2ff0);
/* system PLLs */
BDEV_WR_RB(BCHP_CLK_SYS_PLL_0_3, 0x02);
if (!ENET_WOL(flags))
/* this PLL is needed for EPHY */
BDEV_SET_RB(BCHP_CLK_SYS_PLL_1_CTRL, 0x83);
BDEV_WR_RB(BCHP_VCXO_CTL_MISC_AC1_CTRL, 0x06);
BDEV_SET_RB(BCHP_VCXO_CTL_MISC_VC0_CTRL, 0x0b);
}
static void bcm7468_pm_resume(u32 flags)
{
/* system PLLs */
BDEV_UNSET_RB(BCHP_VCXO_CTL_MISC_VC0_CTRL, 0x0b);
BDEV_WR_RB(BCHP_VCXO_CTL_MISC_AC1_CTRL, 0x00);
BDEV_UNSET_RB(BCHP_CLK_SYS_PLL_1_CTRL, 0x83);
BDEV_WR_RB(BCHP_CLK_SYS_PLL_0_3, 0x01);
/* EBI */
BDEV_UNSET_RB(BCHP_HIF_TOP_CTRL_PM_CTRL, 0x2ff0);
/* SDIO */
BDEV_WR_RB(BCHP_CLK_SYS_PLL_1_1, 0);
BDEV_WR_F_RB(CLK_HIF_SDIO_CLK_PM_CTRL, DIS_HIF_SDIO_48M_CLK, 0);
}
#define PM_OPS_DEFINED
static struct brcm_chip_pm_ops chip_pm_ops = {
DEF_BLOCK_PM_OP(usb, 7468),
DEF_BLOCK_PM_OP(genet, 7468),
DEF_SYSTEM_PM_OP(7468),
};
#endif
/* 40nm chips start here */
#if defined(CONFIG_BCM7425) || \
defined(CONFIG_BCM7429) || \
defined(CONFIG_BCM7435) || \
defined(CONFIG_BCM7346) || \
defined(CONFIG_BCM7231) || \
defined(CONFIG_BCM7552) || \
defined(CONFIG_BCM7584) || \
defined(CONFIG_BCM7563) || \
defined(CONFIG_BCM7344) || \
defined(CONFIG_BCM7358) || \
defined(CONFIG_BCM7360) || \
defined(CONFIG_BCM7362)
static __maybe_unused int mem_power_down = 1;
#undef PLL_CH_ENA
#undef PLL_CH_DIS
#undef PLL_ENA
#undef PLL_DIS
#define PLL_CH_DIS(pll, ch) do { \
BDEV_WR_F_RB(pll ## _CH_ ## ch, POST_DIVIDER_HOLD_CH ## ch, 1); \
BDEV_WR_F_RB(pll ## _CH_ ## ch, CLOCK_DIS_CH ## ch, 1); \
} while (0)
#define PLL_CH_ENA(pll, ch) do { \
BDEV_WR_F_RB(pll ## _CH_ ## ch, CLOCK_DIS_CH ## ch, 0); \
BDEV_WR_F_RB(pll ## _CH_ ## ch, POST_DIVIDER_HOLD_CH ## ch, 0); \
} while (0)
#define PLL_DIS(pll) do { \
BDEV_WR_F_RB(pll ## _RESET, RESETD, 1); \
BDEV_WR_F_RB(pll ## _RESET, RESETA, 1); \
BDEV_WR_F_RB(pll ## _PWRDN, PWRDN_PLL, 1); \
} while (0)
#define PLL_ENA(pll) do { \
BDEV_WR_F_RB(pll ## _PWRDN, PWRDN_PLL, 0); \
BDEV_WR_F_RB(pll ## _RESET, RESETA, 0); \
BDEV_WR_F_RB(pll ## _RESET, RESETD, 0); \
do { \
mdelay(1); \
} while (!BDEV_RD_F(pll ## _LOCK_STATUS, LOCK)); \
} while (0)
/* IMPORTANT: must be done in TWO steps per RDB note */
#define POWER_UP_MEMORY_3(core, mask, inst) \
do { \
BDEV_WR_F_RB(CLKGEN_ ## core ## _POWER_SWITCH_MEMORY ## inst,\
mask ## _POWER_SWITCH_MEMORY ## inst, 2); \
udelay(10); \
BDEV_WR_F_RB(CLKGEN_ ## core ## _POWER_SWITCH_MEMORY ## inst,\
mask ## _POWER_SWITCH_MEMORY ## inst, 0); \
} while (0)
#define POWER_UP_MEMORY_1(core) POWER_UP_MEMORY_3(core, core, \
)
#define POWER_UP_MEMORY_1ii(core) \
POWER_UP_MEMORY_2(core ## _INST, core ## _INST)
#define POWER_UP_MEMORY_2(core, mask) POWER_UP_MEMORY_3(core, mask, \
)
#define POWER_UP_MEMORY_2i(core, mask) POWER_UP_MEMORY_3(core ## _INST, mask, \
)
#define POWER_UP_MEMORY_3i(core, mask, inst) \
POWER_UP_MEMORY_3(core ## _INST, mask, inst)
#define SRAM_OFF_3(core, mask, inst) \
do { \
if (mem_power_down) \
BDEV_WR_F_RB( \
CLKGEN_ ## core ## _POWER_SWITCH_MEMORY ## inst, \
mask ## _POWER_SWITCH_MEMORY ## inst, 3); \
else \
BDEV_WR_F_RB( \
CLKGEN_ ## core ## _MEMORY_STANDBY_ENABLE ## inst, \
mask ## _MEMORY_STANDBY_ENABLE ## inst, 1); \
} while (0)
#define SRAM_OFF_1i(core) SRAM_OFF_3(core ## _INST, core, \
)
#define SRAM_OFF_1(core) SRAM_OFF_3(core, core, \
)
#define SRAM_OFF_2i(core, mask) SRAM_OFF_3(core ## _INST, mask, \
)
#define SRAM_OFF_3i(core, mask, inst) SRAM_OFF_3(core ## _INST, mask, inst)
#define SRAM_OFF_2(core, mask) SRAM_OFF_3(core, mask, \
)
#define SRAM_ON_3(core, mask, inst) \
do { \
if (mem_power_down) \
POWER_UP_MEMORY_3(core, mask, inst); \
else \
BDEV_WR_F_RB(CLKGEN_ ## core ## _MEMORY_STANDBY_ENABLE ## inst, \
mask ## _MEMORY_STANDBY_ENABLE ## inst, 0); \
} while (0)
#define SRAM_ON_1i(core) SRAM_ON_3(core ## _INST, core, \
)
#define SRAM_ON_1(core) SRAM_ON_3(core, core, \
)
#define SRAM_ON_2i(core, mask) SRAM_ON_3(core ## _INST, mask, \
)
#define SRAM_ON_2(core, mask) SRAM_ON_3(core, mask, \
)
#define SRAM_ON_3i(core, mask, inst) SRAM_ON_3(core ## _INST, mask, inst)
#endif
/******************************************************************
* USB recovery after S3 warm boot
* These parameters are mostly configured by CFE on cold boot, some
* of them are set during HC reset code which we do not execute on
* warm boot because it re-allocates memory.
* The code will probably work on all 40nm chips, but we will see...
******************************************************************/
static u32 usb_cfg[4];
static __maybe_unused void bcm40nm_pm_usb_disable_s3(void)
{
if (!brcm_pm_deep_sleep())
return;
#ifdef BCHP_USB_CTRL_SETUP
usb_cfg[0] = BDEV_RD(BCHP_USB_CTRL_SETUP);
usb_cfg[1] = BDEV_RD(BCHP_USB_CTRL_EBRIDGE);
#endif
#ifdef BCHP_USB1_CTRL_SETUP
usb_cfg[2] = BDEV_RD(BCHP_USB1_CTRL_SETUP);
usb_cfg[3] = BDEV_RD(BCHP_USB1_CTRL_EBRIDGE);
#endif
}
static __maybe_unused void bcm40nm_pm_usb_enable_s3(void)
{
if (!brcm_pm_deep_sleep())
return;
printk(KERN_DEBUG "Restoring USB HC state from S3 suspend\n");
#ifdef BCHP_USB_CTRL_SETUP
BDEV_WR_RB(BCHP_USB_CTRL_SETUP, usb_cfg[0]);
BDEV_WR_RB(BCHP_USB_CTRL_EBRIDGE, usb_cfg[1]);
#endif
#ifdef BCHP_USB1_CTRL_SETUP
BDEV_WR_RB(BCHP_USB1_CTRL_SETUP, usb_cfg[2]);
BDEV_WR_RB(BCHP_USB1_CTRL_EBRIDGE, usb_cfg[3]);
#endif
mdelay(500);
bchip_usb_init();
}
#if defined(CONFIG_BCM7425) || defined(CONFIG_BCM7429) \
|| defined(CONFIG_BCM7346) || defined(CONFIG_BCM7435)
#define BRCM_BASE_CLK 3600 /* base clock in MHz */
/*
* work around RDB name inconsistencies.
*/
#if defined(BCHP_CLKGEN_USB0_INST_CLOCK_DISABLE_DISABLE_USB_54_MDIO_CLOCK_MASK)
#define BCHP_CLKGEN_USB0_INST_CLOCK_DISABLE_DISABLE_USB0_54_MDIO_CLOCK_MASK \
BCHP_CLKGEN_USB0_INST_CLOCK_DISABLE_DISABLE_USB_54_MDIO_CLOCK_MASK
#define BCHP_CLKGEN_USB0_INST_CLOCK_DISABLE_DISABLE_USB0_54_MDIO_CLOCK_SHIFT \
BCHP_CLKGEN_USB0_INST_CLOCK_DISABLE_DISABLE_USB_54_MDIO_CLOCK_SHIFT
#endif
#if defined(BCHP_CLKGEN_USB1_INST_CLOCK_DISABLE_DISABLE_USB_54_MDIO_CLOCK_MASK)
#define BCHP_CLKGEN_USB1_INST_CLOCK_DISABLE_DISABLE_USB1_54_MDIO_CLOCK_MASK \
BCHP_CLKGEN_USB1_INST_CLOCK_DISABLE_DISABLE_USB_54_MDIO_CLOCK_MASK
#define BCHP_CLKGEN_USB1_INST_CLOCK_DISABLE_DISABLE_USB1_54_MDIO_CLOCK_SHIFT \
BCHP_CLKGEN_USB1_INST_CLOCK_DISABLE_DISABLE_USB_54_MDIO_CLOCK_SHIFT
#endif
#if defined(BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB_SCB_CLOCK_ENABLE_MASK)
#define BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB0_SCB_CLOCK_ENABLE_MASK \
BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB_SCB_CLOCK_ENABLE_MASK
#define BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB0_SCB_CLOCK_ENABLE_SHIFT \
BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB_SCB_CLOCK_ENABLE_SHIFT
#define BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB0_108_CLOCK_ENABLE_MASK \
BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB_108_CLOCK_ENABLE_MASK
#define BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB0_108_CLOCK_ENABLE_SHIFT \
BCHP_CLKGEN_USB0_INST_CLOCK_ENABLE_USB_108_CLOCK_ENABLE_SHIFT
#endif
#if defined(BCHP_CLKGEN_MOCAMAC_TOP_INST_CLOCK_ENABLE)
#define BCHP_CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE \
BCHP_CLKGEN_MOCAMAC_TOP_INST_CLOCK_ENABLE
#define BCHP_CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE_MOCA_SCB_CLOCK_ENABLE_MASK \
BCHP_CLKGEN_MOCAMAC_TOP_INST_CLOCK_ENABLE_MOCA_SCB_CLOCK_ENABLE_MASK
#define BCHP_CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE_MOCA_SCB_CLOCK_ENABLE_SHIFT \
BCHP_CLKGEN_MOCAMAC_TOP_INST_CLOCK_ENABLE_MOCA_SCB_CLOCK_ENABLE_SHIFT
#define BCHP_CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE_MOCA_108_CLOCK_ENABLE_MASK \
BCHP_CLKGEN_MOCAMAC_TOP_INST_CLOCK_ENABLE_MOCA_108_CLOCK_ENABLE_MASK
#define BCHP_CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE_MOCA_108_CLOCK_ENABLE_SHIFT \
BCHP_CLKGEN_MOCAMAC_TOP_INST_CLOCK_ENABLE_MOCA_108_CLOCK_ENABLE_SHIFT
#endif
static void bcm40nm_pm_usb_disable(u32 flags)
{
PRINT_PM_CALLBACK;
bcm40nm_pm_usb_disable_s3();
/* USB0 */
/* power down USB PHY */
BDEV_SET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* power down USB PLL */
BDEV_UNSET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
SRAM_OFF_1i(USB0);
/* disable the clocks */
BDEV_WR_F_RB(CLKGEN_USB0_INST_CLOCK_DISABLE,
DISABLE_USB0_54_MDIO_CLOCK, 1);
BDEV_WR_F_RB(CLKGEN_USB0_INST_CLOCK_ENABLE, USB0_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_USB0_INST_CLOCK_ENABLE, USB0_108_CLOCK_ENABLE, 0);
/* USB1 */
/* power down USB PHY */
BDEV_SET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* power down USB PLL */
BDEV_UNSET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
SRAM_OFF_1i(USB1);
/* disable the clocks */
BDEV_WR_F_RB(CLKGEN_USB1_INST_CLOCK_DISABLE,
DISABLE_USB1_54_MDIO_CLOCK, 1);
BDEV_WR_F_RB(CLKGEN_USB1_INST_CLOCK_ENABLE, USB1_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_USB1_INST_CLOCK_ENABLE, USB1_108_CLOCK_ENABLE, 0);
#if defined(BCHP_CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL_CH_4)
/* power down PLL */
PLL_CH_DIS(CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL, 4);
#endif
}
static void bcm40nm_pm_usb_enable(u32 flags)
{
PRINT_PM_CALLBACK;
/* power up PLL */
#if defined(BCHP_CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL_CH_4)
PLL_CH_ENA(CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL, 4);
#endif
/* USB0 */
/* enable the clocks */
BDEV_WR_F_RB(CLKGEN_USB0_INST_CLOCK_DISABLE,
DISABLE_USB0_54_MDIO_CLOCK, 0);
BDEV_WR_F_RB(CLKGEN_USB0_INST_CLOCK_ENABLE, USB0_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_USB0_INST_CLOCK_ENABLE, USB0_108_CLOCK_ENABLE, 1);
SRAM_ON_1i(USB0);
/* power up USB PLL */
BDEV_SET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
/* power up USB PHY */
BDEV_UNSET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* USB1 */
/* enable the clocks */
BDEV_WR_F_RB(CLKGEN_USB1_INST_CLOCK_DISABLE,
DISABLE_USB1_54_MDIO_CLOCK, 0);
BDEV_WR_F_RB(CLKGEN_USB1_INST_CLOCK_ENABLE, USB1_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_USB1_INST_CLOCK_ENABLE, USB1_108_CLOCK_ENABLE, 1);
SRAM_ON_1i(USB1);
/* power up USB PLL */
BDEV_SET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* power up USB PHY */
BDEV_UNSET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
bcm40nm_pm_usb_enable_s3();
}
static void bcm40nm_pm_sata_disable(u32 flags)
{
PRINT_PM_CALLBACK;
SRAM_OFF_2i(SATA3_TOP, SATA3);
/* gate the clocks */
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_INST_CLOCK_ENABLE,
SATA3_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_INST_CLOCK_ENABLE,
SATA3_108_CLOCK_ENABLE, 0);
}
static void bcm40nm_pm_sata_enable(u32 flags)
{
PRINT_PM_CALLBACK;
/* reenable the clocks */
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_INST_CLOCK_ENABLE,
SATA3_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_INST_CLOCK_ENABLE,
SATA3_108_CLOCK_ENABLE, 1);
SRAM_ON_2i(SATA3_TOP, SATA3);
}
static void bcm40nm_pm_genet_disable(u32 flags)
{
PRINT_PM_CALLBACK;
#if defined(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_POWER_SWITCH_MEMORY_A)
SRAM_OFF_3i(DUAL_GENET_TOP_DUAL_RGMII, GENET0, _A);
#endif
#if defined(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET0)
if (ENET_WOL(flags)) {
/* switch to slow clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_CLOCK_SELECT_GENET0, 1);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_GMII_CLOCK_SELECT_GENET0, 1);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET0,
0x106);
} else {
/* every clock except AON */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
0xe);
/* Every genet0 clock except 108 */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET0,
0x1fe);
}
#elif defined(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET0)
if (ENET_WOL(flags)) {
/* switch to slow clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_CLOCK_SELECT_GENET0, 1);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_GMII_CLOCK_SELECT_GENET0, 1);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET0,
0x106);
} else {
/* every clock except AON */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_DISABLE_GENET0,
0x1e);
/* Every genet0 clock except 108 */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET0,
0x1fe);
}
#else
if (ENET_WOL(flags)) {
/* switch to slow clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET0_CLOCK_SELECT, 1);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET0_GMII_CLOCK_SELECT, 1);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x43); /* used to be 0x53 */
} else {
/* system slow clock, pm clock */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
3);
/* Every gnet0 clock */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x7F);
}
#endif
}
static void bcm40nm_pm_genet_enable(u32 flags)
{
PRINT_PM_CALLBACK;
#if defined(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_POWER_SWITCH_MEMORY_A)
SRAM_ON_3i(DUAL_GENET_TOP_DUAL_RGMII, GENET0, _A);
#endif
#if defined(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET0)
if (ENET_WOL(flags)) {
/* switch to fast clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_CLOCK_SELECT_GENET0, 0);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_GMII_CLOCK_SELECT_GENET0, 0);
/* 250, EEE, UNIMAC-TX */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET0,
0x106);
} else {
/* every genet0 clock */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
0xf);
/* Every genet0 clock */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET0,
0x1ff);
}
#elif defined(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET0)
if (ENET_WOL(flags)) {
/* switch to fast clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_CLOCK_SELECT_GENET0, 0);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET0,
GENET0_GMII_CLOCK_SELECT_GENET0, 0);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET0,
0x106);
} else {
/* every genet0 clock */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_DISABLE_GENET0,
0x1f);
/* Every genet0 clock */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET0,
0x1ff);
}
#else
if (ENET_WOL(flags)) {
/* switch to fast clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET0_CLOCK_SELECT, 0);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET0_GMII_CLOCK_SELECT, 0);
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x43);
} else {
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
3);
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x7F);
}
#endif
}
static void bcm40nm_pm_genet1_disable(u32 flags)
{
PRINT_PM_CALLBACK;
#if defined(CONFIG_BCM7425)
if (mem_power_down)
/* power down memory */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_POWER_SWITCH_MEMORY_B,
GENET1_POWER_SWITCH_MEMORY_B, 3);
else
/* memory to standby */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_MEMORY_STANDBY_ENABLE_A,
GENET1_MEMORY_STANDBY_ENABLE_A, 1);
#endif
#if defined(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET1)
if (MOCA_WOL(flags)) {
/* switch to slow clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_CLOCK_SELECT_GENET1, 1);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_GMII_CLOCK_SELECT_GENET1, 1);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET1,
0x106);
} else {
/* every clock except AON */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
0xe0);
/* Every genet1 clock except 108 */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET1,
0x1fe);
}
#elif defined(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET1)
if (MOCA_WOL(flags)) {
/* switch to slow clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_CLOCK_SELECT_GENET1, 1);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_GMII_CLOCK_SELECT_GENET1, 1);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET1,
0x106);
} else {
/* every clock except AON */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_DISABLE_GENET1,
0x1e);
/* Every genet1 clock except 108 */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET1,
0x1fe);
}
#else
if (MOCA_WOL(flags)) {
/* switch to slow clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET1_CLOCK_SELECT, 1);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET1_GMII_CLOCK_SELECT, 1);
/*
* Do not clear GENET1_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x2180); /* 0x2980 */
} else {
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x3F80);
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
0xC);
}
#endif
}
static void bcm40nm_pm_genet1_enable(u32 flags)
{
PRINT_PM_CALLBACK;
#if defined(CONFIG_BCM7425)
if (mem_power_down)
/* power up memory */
POWER_UP_MEMORY_3i(DUAL_GENET_TOP_DUAL_RGMII, GENET1, _B);
else
/* memory from standby */
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_MEMORY_STANDBY_ENABLE_A,
GENET1_MEMORY_STANDBY_ENABLE_A, 0);
#endif
#if defined(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET1)
if (MOCA_WOL(flags)) {
/* switch to fast clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_CLOCK_SELECT_GENET1, 0);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_GMII_CLOCK_SELECT_GENET1, 0);
/* 250, EEE, UNIMAC-TX */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET1,
0x106);
} else {
/* every genet 1 clock */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
0xf0);
/* Every genet 1 clock */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE_GENET1,
0x1ff);
}
#elif defined(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET1)
if (MOCA_WOL(flags)) {
/* switch to fast clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_CLOCK_SELECT_GENET1, 0);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_SELECT_GENET1,
GENET1_GMII_CLOCK_SELECT_GENET1, 0);
/*
* Do not clear GENET0_L2INTR_CLOCK_ENABLE - it screws up
* receiver after resume !!!
*/
/* 250, EEE, UNIMAC-TX */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET1,
0x106);
} else {
/* every genet 1 clock */
BDEV_UNSET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_DISABLE_GENET1,
0x1f);
/* Every genet 1 clock */
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE_GENET1,
0x1ff);
}
#else
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_DISABLE,
0xC);
if (MOCA_WOL(flags)) {
/* switch to fast clock */
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET1_CLOCK_SELECT, 0);
BDEV_WR_F_RB(
CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_SELECT,
GENET1_GMII_CLOCK_SELECT, 0);
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x2180);
} else {
BDEV_SET(
BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_INST_CLOCK_ENABLE,
0x3F80);
}
#endif
}
static void bcm40nm_pm_moca_disable(u32 flags)
{
PRINT_PM_CALLBACK;
#if defined(BCHP_CLKGEN_MOCA_TOP_INST_POWER_SWITCH_MEMORY)
SRAM_OFF_2i(MOCA_TOP, MOCA);
#endif
BDEV_WR_F_RB(CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE,
MOCA_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE,
MOCA_108_CLOCK_ENABLE, 0);
if (!MOCA_WOL(flags)) {
PLL_CH_DIS(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 0);
PLL_CH_DIS(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 1);
PLL_CH_DIS(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 2);
#if !defined(CONFIG_BCM7435)
PLL_CH_DIS(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 3);
#endif
}
}
static void bcm40nm_pm_moca_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (!MOCA_WOL(flags)) {
PLL_CH_ENA(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 0);
PLL_CH_ENA(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 1);
PLL_CH_ENA(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 2);
#if !defined(CONFIG_BCM7435)
PLL_CH_ENA(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL, 3);
#endif
}
BDEV_WR_F_RB(CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE,
MOCA_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_MOCA_TOP_INST_CLOCK_ENABLE,
MOCA_108_CLOCK_ENABLE, 1);
#if defined(BCHP_CLKGEN_MOCA_TOP_INST_POWER_SWITCH_MEMORY)
SRAM_ON_2i(MOCA_TOP, MOCA);
#endif
}
static int bcm40nm_pm_set_moca_cpu_rate(unsigned long rate)
{
#ifdef BCHP_CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL_CH_0
BDEV_WR_F(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL_CH_0,
MDIV_CH0, BRCM_BASE_CLK/(rate/1000000));
return 0;
#else
return -EINVAL;
#endif
}
static int bcm40nm_pm_set_moca_phy_rate(unsigned long rate)
{
#ifdef BCHP_CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL_CH_1
BDEV_WR_F(CLKGEN_PLL_MOCA_PLL_CHANNEL_CTRL_CH_1,
MDIV_CH1, BRCM_BASE_CLK/(rate/1000000));
return 0;
#else
return -ENOENT;
#endif
}
#endif
#if defined(CONFIG_BCM7231)
static void bcm7231_pm_usb_disable(u32 flags)
{
PRINT_PM_CALLBACK;
bcm40nm_pm_usb_disable_s3();
/* USB0 */
/* power down USB PHY */
BDEV_SET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* power down USB PLL */
BDEV_UNSET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
SRAM_OFF_1(USB0);
/* disable the clocks */
BDEV_WR_F_RB(CLKGEN_USB0_CLOCK_DISABLE,
DISABLE_USB_54_MDIO_CLOCK, 1);
BDEV_WR_F_RB(CLKGEN_USB0_CLOCK_ENABLE, USB0_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_USB0_CLOCK_ENABLE, USB0_108_CLOCK_ENABLE, 0);
/* USB1 */
/* power down USB PHY */
BDEV_SET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* power down USB PLL */
BDEV_UNSET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
SRAM_OFF_1(USB1);
/* disable the clocks */
BDEV_WR_F_RB(CLKGEN_USB1_CLOCK_DISABLE,
DISABLE_USB_54_MDIO_CLOCK, 1);
BDEV_WR_F_RB(CLKGEN_USB1_CLOCK_ENABLE, USB1_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_USB1_CLOCK_ENABLE, USB1_108_CLOCK_ENABLE, 0);
/* power down PLL */
PLL_CH_DIS(CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL, 4);
}
static void bcm7231_pm_usb_enable(u32 flags)
{
PRINT_PM_CALLBACK;
/* power up PLL */
PLL_CH_ENA(CLKGEN_PLL_SYS0_PLL_CHANNEL_CTRL, 4);
/* USB0 */
/* enable the clocks */
BDEV_WR_F_RB(CLKGEN_USB0_CLOCK_DISABLE,
DISABLE_USB_54_MDIO_CLOCK, 0);
BDEV_WR_F_RB(CLKGEN_USB0_CLOCK_ENABLE, USB0_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_USB0_CLOCK_ENABLE, USB0_108_CLOCK_ENABLE, 1);
SRAM_ON_1(USB0);
/* power up USB PLL */
BDEV_SET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
/* power up USB PHY */
BDEV_UNSET(BCHP_USB_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
/* USB1 */
/* enable the clocks */
BDEV_WR_F_RB(CLKGEN_USB1_CLOCK_DISABLE,
DISABLE_USB_54_MDIO_CLOCK, 0);
BDEV_WR_F_RB(CLKGEN_USB1_CLOCK_ENABLE, USB1_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_USB1_CLOCK_ENABLE, USB1_108_CLOCK_ENABLE, 1);
SRAM_ON_1(USB1);
/* power up USB PLL */
BDEV_SET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_PWRDWNB_MASK);
/* power up USB PHY */
BDEV_UNSET(BCHP_USB1_CTRL_PLL_CTL,
BCHP_USB_CTRL_PLL_CTL_PLL_IDDQ_PWRDN_MASK);
bcm40nm_pm_usb_enable_s3();
}
static void bcm7231_pm_sata_disable(u32 flags)
{
PRINT_PM_CALLBACK;
SRAM_OFF_2(SATA3_TOP, SATA3);
/* gate the clocks */
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_CLOCK_ENABLE,
SATA3_SCB_CLOCK_ENABLE, 0);
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_CLOCK_ENABLE,
SATA3_108_CLOCK_ENABLE, 0);
}
static void bcm7231_pm_sata_enable(u32 flags)
{
PRINT_PM_CALLBACK;
/* reenable the clocks */
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_CLOCK_ENABLE,
SATA3_SCB_CLOCK_ENABLE, 1);
BDEV_WR_F_RB(CLKGEN_SATA3_TOP_CLOCK_ENABLE,
SATA3_108_CLOCK_ENABLE, 1);
SRAM_ON_2(SATA3_TOP, SATA3);
}
static void bcm7231_pm_genet_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET0_CLOCK_SELECT, 1);
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET0_GMII_CLOCK_SELECT, 1);
/* Disabling L2_INTR clock breaks HFB pattern matching ??? */
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE,
0x43); /* used to be 0x53 */
return;
}
SRAM_OFF_2(DUAL_GENET_TOP_DUAL_RGMII, GENET0);
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_DISABLE, 7);
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE, 0x7F);
}
static void bcm7231_pm_genet_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ENET_WOL(flags)) {
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE,
0x43); /* used to be 0x53 */
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET0_CLOCK_SELECT, 0);
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET0_GMII_CLOCK_SELECT, 0);
return;
}
SRAM_ON_2(DUAL_GENET_TOP_DUAL_RGMII, GENET0);
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_DISABLE, 7);
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE, 0x7F);
}
static void bcm7231_pm_genet1_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (MOCA_WOL(flags)) {
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET1_CLOCK_SELECT, 1);
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET1_GMII_CLOCK_SELECT, 1);
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE,
0x2980);
return;
}
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_DISABLE, 0x38);
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE, 0x3F80);
}
static void bcm7231_pm_genet1_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (MOCA_WOL(flags)) {
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE,
0x2980);
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET1_CLOCK_SELECT, 0);
BDEV_WR_F_RB(CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_SELECT,
GENET1_GMII_CLOCK_SELECT, 0);
return;
}
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_DISABLE, 0x38);
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_ENABLE, 0x3F80);
}
static void bcm7231_pm_suspend(u32 flags)
{
}
static void bcm7231_pm_resume(u32 flags)
{
}
static void bcm7231_pm_initialize(void)
{
/* test scan clocks */
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_DUAL_RGMII_CLOCK_DISABLE, 0xC0);
brcm_ddr_phy_initialize();
}
#define PM_OPS_DEFINED
static struct brcm_chip_pm_ops chip_pm_ops = {
DEF_BLOCK_PM_OP(usb, 7231),
DEF_BLOCK_PM_OP(sata, 7231),
DEF_BLOCK_PM_OP(genet, 7231),
DEF_BLOCK_PM_OP(genet1, 7231),
DEF_SYSTEM_PM_OP(7231),
.clk_get = brcm_pm_clk_get,
.initialize = bcm7231_pm_initialize,
};
#endif
#if defined(CONFIG_BCM7344)
static void bcm7344_pm_network_disable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ANY_WOL(flags))
return;
PLL_CH_DIS(CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL, 0);
PLL_CH_DIS(CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL, 1);
PLL_CH_DIS(CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL, 3);
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_DISABLE, 0xE0);
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE, 0xC000);
}
static void bcm7344_pm_network_enable(u32 flags)
{
PRINT_PM_CALLBACK;
if (ANY_WOL(flags))
return;
BDEV_SET(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_ENABLE, 0xC000);
BDEV_UNSET(BCHP_CLKGEN_DUAL_GENET_TOP_RGMII_INST_CLOCK_DISABLE, 0xE0);
PLL_CH_ENA(CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL, 0);
PLL_CH_ENA(CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL, 1);
PLL_CH_ENA(CLKGEN_PLL_SYS1_PLL_CHANNEL_CTRL, 3);
}
static void bcm7344_pm_genet_disable(u32 flags)