mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-19 02:04:19 +08:00
1a93520504
Some pcie cards have problems after a reboot without this. Signed-off-by: John Crispin <blogic@openwrt.org> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11446/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
114 lines
2.3 KiB
C
114 lines
2.3 KiB
C
/*
|
|
* 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.
|
|
*
|
|
* Copyright (C) 2008-2009 Gabor Juhos <juhosg@openwrt.org>
|
|
* Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
|
|
* Copyright (C) 2013 John Crispin <blogic@openwrt.org>
|
|
*/
|
|
|
|
#include <linux/pm.h>
|
|
#include <linux/io.h>
|
|
#include <linux/of.h>
|
|
#include <linux/delay.h>
|
|
#include <linux/reset-controller.h>
|
|
|
|
#include <asm/reboot.h>
|
|
|
|
#include <asm/mach-ralink/ralink_regs.h>
|
|
|
|
/* Reset Control */
|
|
#define SYSC_REG_RESET_CTRL 0x034
|
|
|
|
#define RSTCTL_RESET_PCI BIT(26)
|
|
#define RSTCTL_RESET_SYSTEM BIT(0)
|
|
|
|
static int ralink_assert_device(struct reset_controller_dev *rcdev,
|
|
unsigned long id)
|
|
{
|
|
u32 val;
|
|
|
|
if (id < 8)
|
|
return -1;
|
|
|
|
val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
|
|
val |= BIT(id);
|
|
rt_sysc_w32(val, SYSC_REG_RESET_CTRL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ralink_deassert_device(struct reset_controller_dev *rcdev,
|
|
unsigned long id)
|
|
{
|
|
u32 val;
|
|
|
|
if (id < 8)
|
|
return -1;
|
|
|
|
val = rt_sysc_r32(SYSC_REG_RESET_CTRL);
|
|
val &= ~BIT(id);
|
|
rt_sysc_w32(val, SYSC_REG_RESET_CTRL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ralink_reset_device(struct reset_controller_dev *rcdev,
|
|
unsigned long id)
|
|
{
|
|
ralink_assert_device(rcdev, id);
|
|
return ralink_deassert_device(rcdev, id);
|
|
}
|
|
|
|
static struct reset_control_ops reset_ops = {
|
|
.reset = ralink_reset_device,
|
|
.assert = ralink_assert_device,
|
|
.deassert = ralink_deassert_device,
|
|
};
|
|
|
|
static struct reset_controller_dev reset_dev = {
|
|
.ops = &reset_ops,
|
|
.owner = THIS_MODULE,
|
|
.nr_resets = 32,
|
|
.of_reset_n_cells = 1,
|
|
};
|
|
|
|
void ralink_rst_init(void)
|
|
{
|
|
reset_dev.of_node = of_find_compatible_node(NULL, NULL,
|
|
"ralink,rt2880-reset");
|
|
if (!reset_dev.of_node)
|
|
pr_err("Failed to find reset controller node");
|
|
else
|
|
reset_controller_register(&reset_dev);
|
|
}
|
|
|
|
static void ralink_restart(char *command)
|
|
{
|
|
if (IS_ENABLED(CONFIG_PCI)) {
|
|
rt_sysc_m32(0, RSTCTL_RESET_PCI, SYSC_REG_RESET_CTRL);
|
|
mdelay(50);
|
|
}
|
|
|
|
local_irq_disable();
|
|
rt_sysc_w32(RSTCTL_RESET_SYSTEM, SYSC_REG_RESET_CTRL);
|
|
unreachable();
|
|
}
|
|
|
|
static void ralink_halt(void)
|
|
{
|
|
local_irq_disable();
|
|
unreachable();
|
|
}
|
|
|
|
static int __init mips_reboot_setup(void)
|
|
{
|
|
_machine_restart = ralink_restart;
|
|
_machine_halt = ralink_halt;
|
|
|
|
return 0;
|
|
}
|
|
|
|
arch_initcall(mips_reboot_setup);
|