Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | // SPDX-License-Identifier: GPL-2.0-or-later /* Board-specific reboot/shutdown routines * * Copyright (c) 2009 Philippe Vachon <philippe@cowpig.ca> * * Copyright (C) 2009 Lemote Inc. * Author: Wu Zhangjin, wuzhangjin@gmail.com */ #include <linux/io.h> #include <linux/delay.h> #include <linux/types.h> #include <asm/bootinfo.h> #include <loongson.h> #include <cs5536/cs5536.h> #include "ec_kb3310b.h" static void reset_cpu(void) { /* * reset cpu to full speed, this is needed when enabling cpu frequency * scalling */ writel(readl(LOONGSON_CHIPCFG) | 0x7, LOONGSON_CHIPCFG); } /* reset support for fuloong2f */ static void fl2f_reboot(void) { reset_cpu(); /* send a reset signal to south bridge. * * NOTE: if enable "Power Management" in kernel, rtl8169 will not reset * normally with this reset operation and it will not work in PMON, but * you can type halt command and then reboot, seems the hardware reset * logic not work normally. */ { u32 hi, lo; _rdmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), &hi, &lo); lo |= 0x00000001; _wrmsr(DIVIL_MSR_REG(DIVIL_SOFT_RESET), hi, lo); } } static void fl2f_shutdown(void) { u32 hi, lo, val; int gpio_base; /* get gpio base */ _rdmsr(DIVIL_MSR_REG(DIVIL_LBAR_GPIO), &hi, &lo); gpio_base = lo & 0xff00; /* make cs5536 gpio13 output enable */ val = inl(gpio_base + GPIOL_OUT_EN); val &= ~(1 << (16 + 13)); val |= (1 << 13); outl(val, gpio_base + GPIOL_OUT_EN); mmiowb(); /* make cs5536 gpio13 output low level voltage. */ val = inl(gpio_base + GPIOL_OUT_VAL) & ~(1 << (13)); val |= (1 << (16 + 13)); outl(val, gpio_base + GPIOL_OUT_VAL); mmiowb(); } /* reset support for yeeloong2f and mengloong2f notebook */ static void ml2f_reboot(void) { reset_cpu(); /* sending an reset signal to EC(embedded controller) */ ec_write(REG_RESET, BIT_RESET_ON); } #define yl2f89_reboot ml2f_reboot /* menglong(7inches) laptop has different shutdown logic from 8.9inches */ #define EC_SHUTDOWN_IO_PORT_HIGH 0xff2d #define EC_SHUTDOWN_IO_PORT_LOW 0xff2e #define EC_SHUTDOWN_IO_PORT_DATA 0xff2f #define REG_SHUTDOWN_HIGH 0xFC #define REG_SHUTDOWN_LOW 0x29 #define BIT_SHUTDOWN_ON (1 << 1) static void ml2f_shutdown(void) { u8 val; u64 i; outb(REG_SHUTDOWN_HIGH, EC_SHUTDOWN_IO_PORT_HIGH); outb(REG_SHUTDOWN_LOW, EC_SHUTDOWN_IO_PORT_LOW); mmiowb(); val = inb(EC_SHUTDOWN_IO_PORT_DATA); outb(val & (~BIT_SHUTDOWN_ON), EC_SHUTDOWN_IO_PORT_DATA); mmiowb(); /* need enough wait here... how many microseconds needs? */ for (i = 0; i < 0x10000; i++) delay(); outb(val | BIT_SHUTDOWN_ON, EC_SHUTDOWN_IO_PORT_DATA); mmiowb(); } static void yl2f89_shutdown(void) { /* cpu-gpio0 output low */ LOONGSON_GPIODATA &= ~0x00000001; /* cpu-gpio0 as output */ LOONGSON_GPIOIE &= ~0x00000001; } void mach_prepare_reboot(void) { switch (mips_machtype) { case MACH_LEMOTE_FL2F: case MACH_LEMOTE_NAS: case MACH_LEMOTE_LL2F: fl2f_reboot(); break; case MACH_LEMOTE_ML2F7: ml2f_reboot(); break; case MACH_LEMOTE_YL2F89: yl2f89_reboot(); break; default: break; } } void mach_prepare_shutdown(void) { switch (mips_machtype) { case MACH_LEMOTE_FL2F: case MACH_LEMOTE_NAS: case MACH_LEMOTE_LL2F: fl2f_shutdown(); break; case MACH_LEMOTE_ML2F7: ml2f_shutdown(); break; case MACH_LEMOTE_YL2F89: yl2f89_shutdown(); break; default: break; } } |