/*
 * Copyright (c) 2018-2020 Atmosphère-NX
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
 */
#pragma once
#include <vapours/common.hpp>
#include <vapours/assert.hpp>
#include <vapours/literals.hpp>
#include <vapours/util.hpp>
#include <vapours/results.hpp>
#include <vapours/reg.hpp>

#define APBDEV_PMC_CNTRL                (0x000)
#define APBDEV_PMC_WAKE_MASK            (0x00C)
#define APBDEV_PMC_WAKE_LVL             (0x010)
#define APBDEV_PMC_WAKE_STATUS          (0x014)
#define APBDEV_PMC_DPD_PADS_ORIDE       (0x01C)
#define APBDEV_PMC_DPD_SAMPLE           (0x020)
#define APBDEV_PMC_DPD_ENABLE           (0x024)
#define APBDEV_PMC_CLAMP_STATUS         (0x02C)
#define APBDEV_PMC_PWRGATE_TOGGLE       (0x030)
#define APBDEV_PMC_REMOVE_CLAMPING_CMD  (0x034)
#define APBDEV_PMC_PWRGATE_STATUS       (0x038)
#define APBDEV_PMC_PWRGOOD_TIMER        (0x03C)
#define APBDEV_PMC_BLINK_TIMER          (0x040)
#define APBDEV_PMC_NO_IOPOWER           (0x044)
#define APBDEV_PMC_PWR_DET              (0x048)
#define APBDEV_PMC_SCRATCH0             (0x050)
#define APBDEV_PMC_SCRATCH1             (0x054)
#define APBDEV_PMC_SCRATCH4             (0x060)
#define APBDEV_PMC_SCRATCH12            (0x080)
#define APBDEV_PMC_SCRATCH13            (0x084)
#define APBDEV_PMC_SCRATCH18            (0x098)
#define APBDEV_PMC_SCRATCH20            (0x0A0)
#define APBDEV_PMC_AUTO_WAKE_LVL_MASK   (0x0DC)
#define APBDEV_PMC_WAKE_DELAY           (0x0E0)
#define APBDEV_PMC_PWR_DET_VAL          (0x0E4)
#define APBDEV_PMC_CRYPTO_OP            (0x0F4)
#define APBDEV_PMC_SCRATCH31            (0x118)
#define APBDEV_PMC_SCRATCH32            (0x11C)
#define APBDEV_PMC_SCRATCH33            (0x120)
#define APBDEV_PMC_SCRATCH39            (0x138)
#define APBDEV_PMC_SCRATCH40            (0x13C)
#define APBDEV_PMC_WAKE2_MASK           (0x160)
#define APBDEV_PMC_WAKE2_LVL            (0x164)
#define APBDEV_PMC_WAKE2_STATUS         (0x168)
#define APBDEV_PMC_AUTO_WAKE2_LVL_MASK  (0x170)
#define APBDEV_PMC_OSC_EDPD_OVER        (0x1A4)
#define APBDEV_PMC_CLK_OUT_CNTRL        (0x1A8)
#define APBDEV_PMC_IO_DPD_REQ           (0x1B8)
#define APBDEV_PMC_IO_DPD_STATUS        (0x1BC)
#define APBDEV_PMC_IO_DPD2_REQ          (0x1C0)
#define APBDEV_PMC_IO_DPD2_STATUS       (0x1C4)
#define APBDEV_PMC_SEL_DPD_TIM          (0x1C8)
#define APBDEV_PMC_SCRATCH45            (0x234)
#define APBDEV_PMC_SCRATCH46            (0x238)
#define APBDEV_PMC_TSC_MULT             (0x2B4)
#define APBDEV_PMC_STICKY_BITS          (0x2C0)
#define APBDEV_PMC_WEAK_BIAS            (0x2C8)
#define APBDEV_PMC_GPU_RG_CNTRL         (0x2D4)
#define APBDEV_PMC_CNTRL2               (0x440)
#define APBDEV_PMC_FUSE_CTRL            (0x450)
#define APBDEV_PMC_IO_DPD3_REQ          (0x45C)
#define APBDEV_PMC_IO_DPD3_STATUS       (0x460)
#define APBDEV_PMC_IO_DPD4_REQ          (0x464)
#define APBDEV_PMC_IO_DPD4_STATUS       (0x468)
#define APBDEV_PMC_SET_SW_CLAMP         (0x47C)
#define APBDEV_PMC_WAKE_DEBOUNCE_EN     (0x4D8)
#define APBDEV_PMC_DDR_CNTRL            (0x4E4)
#define APBDEV_PMC_SEC_DISABLE          (0x004)
#define APBDEV_PMC_SEC_DISABLE2         (0x2C4)
#define APBDEV_PMC_SEC_DISABLE3         (0x2D8)
#define APBDEV_PMC_SEC_DISABLE4         (0x5B0)
#define APBDEV_PMC_SEC_DISABLE5         (0x5B4)
#define APBDEV_PMC_SEC_DISABLE6         (0x5B8)
#define APBDEV_PMC_SEC_DISABLE7         (0x5BC)
#define APBDEV_PMC_SEC_DISABLE8         (0x5C0)
#define APBDEV_PMC_SCRATCH43            (0x22C)
#define APBDEV_PMC_SCRATCH190           (0x818)
#define APBDEV_PMC_SCRATCH200           (0x840)
#define APBDEV_PMC_SEC_DISABLE3         (0x2D8)
#define APBDEV_PMC_SECURE_SCRATCH4      (0x0C0)
#define APBDEV_PMC_SECURE_SCRATCH5      (0x0C4)
#define APBDEV_PMC_SECURE_SCRATCH6      (0x224)
#define APBDEV_PMC_SECURE_SCRATCH7      (0x228)
#define APBDEV_PMC_SECURE_SCRATCH16     (0x320)
#define APBDEV_PMC_SECURE_SCRATCH21     (0x334)
#define APBDEV_PMC_SECURE_SCRATCH24     (0x340)
#define APBDEV_PMC_SECURE_SCRATCH25     (0x344)
#define APBDEV_PMC_SECURE_SCRATCH26     (0x348)
#define APBDEV_PMC_SECURE_SCRATCH27     (0x34C)
#define APBDEV_PMC_SECURE_SCRATCH32     (0x360)
#define APBDEV_PMC_SECURE_SCRATCH34     (0x368)
#define APBDEV_PMC_SECURE_SCRATCH35     (0x36C)
#define APBDEV_PMC_SECURE_SCRATCH39     (0x37C)
#define APBDEV_PMC_SECURE_SCRATCH51     (0x3AC)
#define APBDEV_PMC_SECURE_SCRATCH55     (0x3BC)
#define APBDEV_PMC_SECURE_SCRATCH74     (0x408)
#define APBDEV_PMC_SECURE_SCRATCH75     (0x40C)
#define APBDEV_PMC_SECURE_SCRATCH76     (0x410)
#define APBDEV_PMC_SECURE_SCRATCH77     (0x414)
#define APBDEV_PMC_SECURE_SCRATCH78     (0x418)
#define APBDEV_PMC_SECURE_SCRATCH99     (0xAE4)
#define APBDEV_PMC_SECURE_SCRATCH100    (0xAE8)
#define APBDEV_PMC_SECURE_SCRATCH101    (0xAEC)
#define APBDEV_PMC_SECURE_SCRATCH102    (0xAF0)
#define APBDEV_PMC_SECURE_SCRATCH103    (0xAF4)
#define APBDEV_PMC_SECURE_SCRATCH112    (0xB18)
#define APBDEV_PMC_SECURE_SCRATCH113    (0xB1C)
#define APBDEV_PMC_SECURE_SCRATCH114    (0xB20)
#define APBDEV_PMC_SECURE_SCRATCH115    (0xB24)
#define APBDEV_PMC_SECURE_SCRATCH119    (0xB34)


#define PMC_REG_BITS_MASK(NAME)                                      REG_NAMED_BITS_MASK    (APBDEV_PMC, NAME)
#define PMC_REG_BITS_VALUE(NAME, VALUE)                              REG_NAMED_BITS_VALUE   (APBDEV_PMC, NAME, VALUE)
#define PMC_REG_BITS_ENUM(NAME, ENUM)                                REG_NAMED_BITS_ENUM    (APBDEV_PMC, NAME, ENUM)
#define PMC_REG_BITS_ENUM_SEL(NAME, __COND__, TRUE_ENUM, FALSE_ENUM) REG_NAMED_BITS_ENUM_SEL(APBDEV_PMC, NAME, __COND__, TRUE_ENUM, FALSE_ENUM)

#define DEFINE_PMC_REG(NAME, __OFFSET__, __WIDTH__)                                                                                                                  REG_DEFINE_NAMED_REG           (APBDEV_PMC, NAME, __OFFSET__, __WIDTH__)
#define DEFINE_PMC_REG_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE)                                                                                                         REG_DEFINE_NAMED_BIT_ENUM      (APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE)
#define DEFINE_PMC_REG_TWO_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE)                                                                                         REG_DEFINE_NAMED_TWO_BIT_ENUM  (APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE)
#define DEFINE_PMC_REG_THREE_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)                                                               REG_DEFINE_NAMED_THREE_BIT_ENUM(APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN)
#define DEFINE_PMC_REG_FOUR_BIT_ENUM(NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN) REG_DEFINE_NAMED_FOUR_BIT_ENUM (APBDEV_PMC, NAME, __OFFSET__, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, ELEVEN, TWELVE, THIRTEEN, FOURTEEN, FIFTEEN)

DEFINE_PMC_REG_BIT_ENUM(CNTRL_MAIN_RESET, 4, DISABLE, ENABLE)

DEFINE_PMC_REG_BIT_ENUM(DPD_SAMPLE_ON, 0, DISABLE, ENABLE);

DEFINE_PMC_REG_BIT_ENUM(DPD_ENABLE_ON,          0, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(DPD_ENABLE_TSC_MULT_EN, 1, DISABLE, ENABLE);

DEFINE_PMC_REG_BIT_ENUM(PWRGATE_TOGGLE_START, 8, DISABLE, ENABLE);

DEFINE_PMC_REG(PWRGATE_TOGGLE_PARTID, 0, 5);

enum APBDEV_PMC_PWRGATE_TOGGLE_PARTID : u8 {
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CRAIL  =  0,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_VE     =  2,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_PCX    =  3,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_MPE    =  6,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_SAX    =  8,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE1    =  9,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE2    = 10,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE3    = 11,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0    = 14,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_C0NC   = 15,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_SOR    = 17,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_DIS    = 18,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_DISB   = 19,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_XUSBA  = 20,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_XUSBB  = 21,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_XUSBC  = 22,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_VIC    = 23,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_IRAM   = 24,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_NVDEC  = 25,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_NVJPG  = 26,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_AUD    = 27,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_DFD    = 28,
    APBDEV_PMC_PWRGATE_TOGGLE_PARTID_VE2    = 29,
};

DEFINE_PMC_REG_BIT_ENUM(REMOVE_CLAMPING_COMMAND_CRAIL, 0, DISABLE, ENABLE);

enum APBDEV_PMC_PWRGATE_STATUS_STATUS {
    APBDEV_PMC_PWRGATE_STATUS_STATUS_OFF = 0,
    APBDEV_PMC_PWRGATE_STATUS_STATUS_ON  = 1,
};

DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CRAIL,  0, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VE,     2, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_PCX,    3, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_MPE,    6, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_SAX,    8, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE1,    9, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE2,   10, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE3,   11, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_CE0,   14, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_C0NC,  15, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_SOR,   17, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DIS,   18, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DISB,  19, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_XUSBA, 20, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_XUSBB, 21, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_XUSBC, 22, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VIC,   23, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_IRAM,  24, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_NVDEC, 25, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_NVJPG, 26, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_AUD,   27, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_DFD,   28, OFF, ON);
DEFINE_PMC_REG_BIT_ENUM(PWRGATE_STATUS_VE2,   29, OFF, ON);

DEFINE_PMC_REG(PWRGATE_STATUS_CE123, 9, 3);

DEFINE_PMC_REG_BIT_ENUM(NO_IOPOWER_SDMMC1,  12, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(PWR_DET_SDMMC1,     12, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(PWR_DET_VAL_SDMMC1, 12, DISABLE, ENABLE);

DEFINE_PMC_REG(SET_SW_CLAMP_CRAIL, 0, 1);

DEFINE_PMC_REG_TWO_BIT_ENUM(IO_DPD_REQ_CODE,  30, IDLE, DPD_OFF, DPD_ON, RESERVED3);
DEFINE_PMC_REG_TWO_BIT_ENUM(IO_DPD2_REQ_CODE, 30, IDLE, DPD_OFF, DPD_ON, RESERVED3);

DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CRAIL,  0, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_TE,     1, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_VE,     2, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_PCX,    3, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_VDE,    4, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_MPE,    6, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_HEG,    7, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_SAX,    8, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE1,    9, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE2,   10, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE3,   11, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CELP,  12, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_CE0,   14, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_C0NC,  15, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_SOR,   17, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_C1NC,  16, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_DIS,   18, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_DISB,  19, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_XUSBA, 20, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_XUSBB, 21, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_XUSBC, 22, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_VIC,   23, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(CLAMP_STATUS_IRAM,  24, DISABLE, ENABLE);

DEFINE_PMC_REG(OSC_EDPD_OVER_XOFS, 1, 6);

DEFINE_PMC_REG_BIT_ENUM(STICKY_BITS_HDA_LPBK_DIS, 0, DISABLE, ENABLE);
DEFINE_PMC_REG_BIT_ENUM(STICKY_BITS_JTAG_STS, 6, ENABLE, DISABLE);

DEFINE_PMC_REG_BIT_ENUM(CNTRL2_WAKE_DET_EN, 9, DISABLE, ENABLE);

DEFINE_PMC_REG_BIT_ENUM(SEC_DISABLE2_WRITE21, 26, OFF, ON);
