/*
 * Copyright (C) 2014, Samsung Electronics Co., Ltd.
 *
 * Custom SMC Handler for Exynos 5433
 * Read SFR Registers
 */

#include <stdbool.h>
#include <stdint.h>

#define CHIP_ID_SFR_BASE	    0x10000000

/* CMU_PERIS Clock Base */
#define CMU_PERIS_SFR_BASE	    0x10040000

/* SECKEY */
#define SECKEY_SFR_BASE		    0x101A0000

#define PCLK_SECKEY_APBIF_OFFS	    0x0908
#define PCLK_SECKEY_APBIF_VAL	    0x00000001

#define SCLK_SECKEY_OFFS	    0x0A04
#define SCLK_SECKEY_VAL		    0x00000001

#define IP_SECKEY_OFFS		    0x0B0C
#define IP_SECKEY_VAL		    0x00000003

/* CUSTOM EFUSE */
#define CUSTOM_EFUSE_SFR_BASE	    0x10080000

#define PCLK_EFUSE_APBIF_OFFS	    0x0914
#define PCLK_EFUSE_APBIF_VAL	    0x00000001

#define SCLK_EFUSE_OFFS		    0x0A10
#define SCLK_EFUSE_VAL		    0x00000001

#define IP_EFUSE_OFFS		    0x0B18
#define IP_EFUSE_VAL		    0x00000003

#define WAIT_TIME		    100000

typedef volatile uint32_t *sfr_reg;

static void delay(int cycle)
{
    volatile int i = cycle;
    while(i) {
	--i;
    }
}


void init_efuse_clk(void)
{
    static bool done = false;
    if (done) {
        return;
    }

    *(sfr_reg)(CMU_PERIS_SFR_BASE + PCLK_EFUSE_APBIF_OFFS) = PCLK_EFUSE_APBIF_VAL;
    delay(WAIT_TIME);

    *(sfr_reg)(CMU_PERIS_SFR_BASE + SCLK_EFUSE_OFFS) = SCLK_EFUSE_VAL;
    delay(WAIT_TIME);

    *(sfr_reg)(CMU_PERIS_SFR_BASE + IP_EFUSE_OFFS) = IP_EFUSE_VAL;
    delay(WAIT_TIME);
    done = true;
}

void init_seckey_clk(void)
{
    static bool done = false;
    if (done) {
        return;
    }

    *(sfr_reg)(CMU_PERIS_SFR_BASE + PCLK_SECKEY_APBIF_OFFS) = PCLK_SECKEY_APBIF_VAL;
    delay(WAIT_TIME);

    *(sfr_reg)(CMU_PERIS_SFR_BASE + SCLK_SECKEY_OFFS) = SCLK_SECKEY_VAL;
    delay(WAIT_TIME);

    *(sfr_reg)(CMU_PERIS_SFR_BASE + IP_SECKEY_OFFS) = IP_SECKEY_VAL;
    delay(WAIT_TIME);
    done = true;
}

#if defined(__aarch64__)			
uint32_t get_efuse(unsigned long offset)
#else
uint32_t get_efuse(int offset)
#endif	
{
    sfr_reg efuse_ptr = (sfr_reg)(CUSTOM_EFUSE_SFR_BASE + offset);
    init_efuse_clk();
    return *efuse_ptr;
}

#if defined(__aarch64__)			
uint32_t get_seckey(unsigned long offset)
#else
uint32_t get_seckey(int offset)
#endif
{
    sfr_reg sec_ptr = (sfr_reg)(SECKEY_SFR_BASE + offset);
    init_seckey_clk();
    return *sec_ptr;
}

uint32_t get_chipid(void)
{
    return *(sfr_reg)CHIP_ID_SFR_BASE;
}
