1 // Copyright 2017 The Fuchsia Authors
2 //
3 // Use of this source code is governed by a MIT-style
4 // license that can be found in the LICENSE file or at
5 // https://opensource.org/licenses/MIT
6
7 #include <arch/arm64/periphmap.h>
8 #include <dev/power.h>
9 #include <dev/psci.h>
10 #include <pdev/driver.h>
11 #include <pdev/power.h>
12 #include <zircon/boot/driver-config.h>
13 #include <stdio.h>
14
15 // clang-format off
16 #define PMU_HRST_OFFSET 0x404
17 #define SCTRL_PEREN1_OFFSET 0x170
18 #define SCTRL_DDR_BYPASS (1 << 31)
19 #define SCTRL_REBOOT_OFFSET 0x4
20 // clang-format on
21
22 static vaddr_t sctrl_base;
23 static vaddr_t pmu_base;
24
hisi_reboot(enum reboot_flags flags)25 static void hisi_reboot(enum reboot_flags flags) {
26 uint32_t temp = readl(pmu_base + PMU_HRST_OFFSET);
27 temp = (temp & 0xFFFFFF00) | (flags == REBOOT_BOOTLOADER ? 1 : 0);
28 writel(temp, pmu_base + PMU_HRST_OFFSET);
29
30 writel(SCTRL_DDR_BYPASS, sctrl_base + SCTRL_PEREN1_OFFSET);
31 writel(0xdeadbeef, sctrl_base + SCTRL_REBOOT_OFFSET);
32 }
33
hisi_shutdown()34 static void hisi_shutdown() {
35 printf("SHUTDOWN NOT IMPLEMENTED\n");
36 }
37
38 static const struct pdev_power_ops hisi_power_ops = {
39 .reboot = hisi_reboot,
40 .shutdown = hisi_shutdown,
41 };
42
hisi_power_init(const void * driver_data,uint32_t length)43 static void hisi_power_init(const void* driver_data, uint32_t length) {
44 ASSERT(length >= sizeof(dcfg_hisilicon_power_driver_t));
45 auto driver = static_cast<const dcfg_hisilicon_power_driver_t*>(driver_data);
46 ASSERT(driver->sctrl_phys && driver->pmu_phys);
47
48
49 // get virtual addresses of our peripheral bases
50 sctrl_base = periph_paddr_to_vaddr(driver->sctrl_phys);
51 pmu_base = periph_paddr_to_vaddr(driver->pmu_phys);
52 ASSERT(sctrl_base && pmu_base);
53
54 pdev_register_power(&hisi_power_ops);
55 }
56
57 LK_PDEV_INIT(hisi_power_init, KDRV_HISILICON_POWER, hisi_power_init, LK_INIT_LEVEL_PLATFORM);
58