/*
 *  Copyright (C) 2012 Altera Corporation <www.altera.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that 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/>.
 */

#ifndef	_CLOCK_MANAGER_H_
#define	_CLOCK_MANAGER_H_

#ifndef __ASSEMBLY__

#include <asm/io.h>

typedef struct {
	/* main group */
	uint32_t	main_vco_base;
	uint32_t	mpuclk;
	uint32_t	mainclk;
	uint32_t	dbgatclk;
	uint32_t	mainqspiclk;
	uint32_t	mainnandsdmmcclk;
	uint32_t	cfg2fuser0clk;
	uint32_t	maindiv;
	uint32_t	dbgdiv;
	uint32_t	tracediv;
	uint32_t	l4src;

	/* peripheral group */
	uint32_t	peri_vco_base;
	uint32_t	emac0clk;
	uint32_t	emac1clk;
	uint32_t	perqspiclk;
	uint32_t	pernandsdmmcclk;
	uint32_t	perbaseclk;
	uint32_t	s2fuser1clk;
	uint32_t	perdiv;
	uint32_t	gpiodiv;
	uint32_t	persrc;

	/* sdram pll group */
	uint32_t	sdram_vco_base;
	uint32_t	ddrdqsclk;
	uint32_t	ddr2xdqsclk;
	uint32_t	ddrdqclk;
	uint32_t	s2fuser2clk;
} cm_config_t;

extern int cm_basic_init(const cm_config_t *cfg, uint32_t skip_sdram_pll);
unsigned long cm_get_mpu_clk_hz(void);
unsigned long cm_get_sdram_clk_hz(void);
unsigned long cm_get_l4_sp_clk_hz(void);
unsigned long cm_get_mmc_controller_clk_hz(void);
unsigned long cm_get_qspi_controller_clk_hz(void);
void cm_print_clock_quick_summary(void);
void cm_derive_clocks_for_drivers(void);

#endif /* __ASSEMBLY__ */

#define CLKMGR_CTRL_ADDRESS 0x0
#define CLKMGR_BYPASS_ADDRESS 0x4
#define CLKMGR_INTER_ADDRESS 0x8
#define CLKMGR_INTREN_ADDRESS 0xc
#define CLKMGR_DBCTRL_ADDRESS 0x10
#define CLKMGR_STAT_ADDRESS 0x14
#define CLKMGR_MAINPLLGRP_ADDRESS 0x40
#define CLKMGR_MAINPLLGRP_VCO_ADDRESS 0x40
#define CLKMGR_MAINPLLGRP_MISC_ADDRESS 0x44
#define CLKMGR_MAINPLLGRP_MPUCLK_ADDRESS 0x48
#define CLKMGR_MAINPLLGRP_MAINCLK_ADDRESS 0x4c
#define CLKMGR_MAINPLLGRP_DBGATCLK_ADDRESS 0x50
#define CLKMGR_MAINPLLGRP_MAINQSPICLK_ADDRESS 0x54
#define CLKMGR_MAINPLLGRP_MAINNANDSDMMCCLK_ADDRESS 0x58
#define CLKMGR_MAINPLLGRP_CFGS2FUSER0CLK_ADDRESS 0x5c
#define CLKMGR_MAINPLLGRP_EN_ADDRESS 0x60
#define CLKMGR_MAINPLLGRP_MAINDIV_ADDRESS 0x64
#define CLKMGR_MAINPLLGRP_DBGDIV_ADDRESS 0x68
#define CLKMGR_MAINPLLGRP_TRACEDIV_ADDRESS 0x6c
#define CLKMGR_MAINPLLGRP_L4SRC_ADDRESS 0x70
#define CLKMGR_PERPLLGRP_ADDRESS 0x80
#define CLKMGR_PERPLLGRP_VCO_ADDRESS 0x80
#define CLKMGR_PERPLLGRP_MISC_ADDRESS 0x84
#define CLKMGR_PERPLLGRP_EMAC0CLK_ADDRESS 0x88
#define CLKMGR_PERPLLGRP_EMAC1CLK_ADDRESS 0x8c
#define CLKMGR_PERPLLGRP_PERQSPICLK_ADDRESS 0x90
#define CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_ADDRESS 0x94
#define CLKMGR_PERPLLGRP_PERBASECLK_ADDRESS 0x98
#define CLKMGR_PERPLLGRP_S2FUSER1CLK_ADDRESS 0x9c
#define CLKMGR_PERPLLGRP_EN_ADDRESS 0xa0
#define CLKMGR_PERPLLGRP_DIV_ADDRESS 0xa4
#define CLKMGR_PERPLLGRP_GPIODIV_ADDRESS 0xa8
#define CLKMGR_PERPLLGRP_SRC_ADDRESS 0xac
#define CLKMGR_SDRPLLGRP_ADDRESS 0xc0
#define CLKMGR_SDRPLLGRP_VCO_ADDRESS 0xc0
#define CLKMGR_SDRPLLGRP_CTRL_ADDRESS 0xc4
#define CLKMGR_SDRPLLGRP_DDRDQSCLK_ADDRESS 0xc8
#define CLKMGR_SDRPLLGRP_DDR2XDQSCLK_ADDRESS 0xcc
#define CLKMGR_SDRPLLGRP_DDRDQCLK_ADDRESS 0xd0
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_ADDRESS 0xd4
#define CLKMGR_SDRPLLGRP_EN_ADDRESS 0xd8
#define CLKMGR_ALTERAGRP_MPUCLK 0xe0
#define CLKMGR_ALTERAGRP_MAINCLK 0xe4

#define CLKMGR_MAINPLLGRP_EN_S2FUSER0CLK_MASK 0x00000200
#define CLKMGR_MAINPLLGRP_EN_DBGTIMERCLK_MASK 0x00000080
#define CLKMGR_MAINPLLGRP_EN_DBGTRACECLK_MASK 0x00000040
#define CLKMGR_MAINPLLGRP_EN_DBGCLK_MASK 0x00000020
#define CLKMGR_MAINPLLGRP_EN_DBGATCLK_MASK 0x00000010
#define CLKMGR_MAINPLLGRP_EN_L4MPCLK_MASK 0x00000004
#define CLKMGR_MAINPLLGRP_VCO_RESET_VALUE 0x8001000d
#define CLKMGR_PERPLLGRP_VCO_RESET_VALUE 0x8001000d
#define CLKMGR_SDRPLLGRP_VCO_RESET_VALUE 0x8001000d
#define CLKMGR_MAINPLLGRP_MAINDIV_L4MPCLK_SET(x) (((x) << 4) & 0x00000070)
#define CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_SET(x)  (((x) << 7) & 0x00000380)
#define CLKMGR_MAINPLLGRP_L4SRC_L4MP_SET(x) (((x) << 0) & 0x00000001)
#define CLKMGR_MAINPLLGRP_L4SRC_L4SP_SET(x) (((x) << 1) & 0x00000002)
#define CLKMGR_PERPLLGRP_SRC_QSPI_SET(x) (((x) << 4) & 0x00000030)
#define CLKMGR_PERPLLGRP_SRC_NAND_SET(x) (((x) << 2) & 0x0000000c)
#define CLKMGR_PERPLLGRP_SRC_SDMMC_SET(x) (((x) << 0) & 0x00000003)
#define CLKMGR_MAINPLLGRP_VCO_DENOM_SET(x) (((x) << 16) & 0x003f0000)
#define CLKMGR_MAINPLLGRP_VCO_NUMER_SET(x) (((x) << 3) & 0x0000fff8)
#define CLKMGR_MAINPLLGRP_VCO_PWRDN_SET(x) (((x) << 2) & 0x00000004)
#define CLKMGR_MAINPLLGRP_VCO_EN_SET(x) (((x) << 1) & 0x00000002)
#define CLKMGR_MAINPLLGRP_VCO_BGPWRDN_SET(x) (((x) << 0) & 0x00000001)
#define CLKMGR_PERPLLGRP_VCO_PSRC_SET(x) (((x) << 22) & 0x00c00000)
#define CLKMGR_PERPLLGRP_VCO_DENOM_SET(x) (((x) << 16) & 0x003f0000)
#define CLKMGR_PERPLLGRP_VCO_NUMER_SET(x) (((x) << 3) & 0x0000fff8)
#define CLKMGR_SDRPLLGRP_VCO_OUTRESET_SET(x) (((x) << 25) & 0x7e000000)
#define CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(x) (((x) << 24) & 0x01000000)
#define CLKMGR_SDRPLLGRP_VCO_SSRC_SET(x) (((x) << 22) & 0x00c00000)
#define CLKMGR_SDRPLLGRP_VCO_DENOM_SET(x) (((x) << 16) & 0x003f0000)
#define CLKMGR_SDRPLLGRP_VCO_NUMER_SET(x) (((x) << 3) & 0x0000fff8)
#define CLKMGR_MAINPLLGRP_MPUCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_MAINCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_DBGATCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_PERNANDSDMMCCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_CFGS2FUSER0CLK_CNT_SET(x) \
	(((x) << 0) & 0x000001ff)
#define CLKMGR_PERPLLGRP_EMAC0CLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_PERPLLGRP_EMAC1CLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_MAINQSPICLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_MAINNANDSDMMCCLK_CNT_SET(x) \
	(((x) << 0) & 0x000001ff)
#define CLKMGR_PERPLLGRP_PERBASECLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_PERPLLGRP_S2FUSER1CLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_SET(x) (((x) << 9) & 0x00000e00)
#define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_SET(x) (((x) << 9) & 0x00000e00)
#define CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_SET(x) (((x) << 9) & 0x00000e00)
#define CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_SET(x) (((x) << 9) & 0x00000e00)
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_MAINPLLGRP_DBGDIV_DBGCLK_SET(x) (((x) << 2) & 0x0000000c)
#define CLKMGR_MAINPLLGRP_DBGDIV_DBGATCLK_SET(x) (((x) << 0) & 0x00000003)
#define CLKMGR_MAINPLLGRP_TRACEDIV_TRACECLK_SET(x) (((x) << 0) & 0x00000007)
#define CLKMGR_MAINPLLGRP_MAINDIV_L3MPCLK_SET(x) (((x) << 0) & 0x00000003)
#define CLKMGR_MAINPLLGRP_MAINDIV_L3SPCLK_SET(x) (((x) << 2) & 0x0000000c)
#define CLKMGR_BYPASS_PERPLL_SET(x) (((x) << 3) & 0x00000008)
#define CLKMGR_BYPASS_SDRPLL_SET(x) (((x) << 1) & 0x00000002)
#define CLKMGR_BYPASS_MAINPLL_SET(x) (((x) << 0) & 0x00000001)
#define CLKMGR_PERPLLGRP_DIV_USBCLK_SET(x) (((x) << 0) & 0x00000007)
#define CLKMGR_PERPLLGRP_DIV_SPIMCLK_SET(x) (((x) << 3) & 0x00000038)
#define CLKMGR_PERPLLGRP_DIV_CAN0CLK_SET(x) (((x) << 6) & 0x000001c0)
#define CLKMGR_PERPLLGRP_DIV_CAN1CLK_SET(x) (((x) << 9) & 0x00000e00)
#define CLKMGR_INTER_SDRPLLLOCKED_MASK 0x00000100
#define CLKMGR_INTER_PERPLLLOCKED_MASK 0x00000080
#define CLKMGR_INTER_MAINPLLLOCKED_MASK 0x00000040
#define CLKMGR_CTRL_SAFEMODE_MASK 0x00000001
#define CLKMGR_CTRL_SAFEMODE_SET(x) (((x) << 0) & 0x00000001)
#define CLKMGR_SDRPLLGRP_VCO_OUTRESET_MASK 0x7e000000
#define CLKMGR_SDRPLLGRP_VCO_OUTRESETALL_SET(x) (((x) << 24) & 0x01000000)
#define CLKMGR_PERPLLGRP_PERQSPICLK_CNT_SET(x) (((x) << 0) & 0x000001ff)
#define CLKMGR_PERPLLGRP_DIV_SPIMCLK_SET(x) (((x) << 3) & 0x00000038)
#define CLKMGR_PERPLLGRP_GPIODIV_GPIODBCLK_SET(x) (((x) << 0) & 0x00ffffff)
#define CLKMGR_BYPASS_PERPLLSRC_SET(x) (((x) << 4) & 0x00000010)
#define CLKMGR_BYPASS_SDRPLLSRC_SET(x) (((x) << 2) & 0x00000004)
#define CLKMGR_PERPLLGRP_SRC_RESET_VALUE 0x00000015
#define CLKMGR_MAINPLLGRP_L4SRC_RESET_VALUE 0x00000000
#define CLKMGR_MAINPLLGRP_VCO_REGEXTSEL_MASK 0x80000000
#define CLKMGR_PERPLLGRP_VCO_REGEXTSEL_MASK 0x80000000
#define CLKMGR_SDRPLLGRP_VCO_REGEXTSEL_MASK 0x80000000
#define CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_MASK 0x001ffe00
#define CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_MASK 0x001ffe00
#define CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_MASK 0x001ffe00
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_MASK 0x001ffe00
#define CLKMGR_MAINPLLGRP_VCO_OUTRESETALL_MASK 0x01000000
#define CLKMGR_PERPLLGRP_VCO_OUTRESETALL_MASK 0x01000000
#define CLKMGR_PERPLLGRP_EN_NANDCLK_MASK 0x00000400
#define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_MASK 0x000001ff
#define CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_MASK 0x000001ff
#define CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_MASK 0x000001ff
#define CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_MASK 0x000001ff
#define CLKMGR_INTER_SDRPLLLOST_MASK 0x00000020
#define CLKMGR_INTER_PERPLLLOST_MASK 0x00000010
#define CLKMGR_INTER_MAINPLLLOST_MASK 0x00000008

#define MAIN_VCO_BASE \
	(CLKMGR_MAINPLLGRP_VCO_DENOM_SET(\
	CONFIG_HPS_MAINPLLGRP_VCO_DENOM) | \
	CLKMGR_MAINPLLGRP_VCO_NUMER_SET(\
	CONFIG_HPS_MAINPLLGRP_VCO_NUMER))

#define PERI_VCO_BASE \
	(CLKMGR_PERPLLGRP_VCO_PSRC_SET(\
	CONFIG_HPS_PERPLLGRP_VCO_PSRC) | \
	CLKMGR_PERPLLGRP_VCO_DENOM_SET(\
	CONFIG_HPS_PERPLLGRP_VCO_DENOM) | \
	CLKMGR_PERPLLGRP_VCO_NUMER_SET(\
	CONFIG_HPS_PERPLLGRP_VCO_NUMER))

#define SDR_VCO_BASE \
	(CLKMGR_SDRPLLGRP_VCO_SSRC_SET(\
	CONFIG_HPS_SDRPLLGRP_VCO_SSRC) | \
	CLKMGR_SDRPLLGRP_VCO_DENOM_SET(\
	CONFIG_HPS_SDRPLLGRP_VCO_DENOM) | \
	CLKMGR_SDRPLLGRP_VCO_NUMER_SET(\
	CONFIG_HPS_SDRPLLGRP_VCO_NUMER))

#define CLKMGR_MAINPLLGRP_VCO_DENOM_GET(x)	(((x) & 0x003f0000) >> 16)
#define CLKMGR_MAINPLLGRP_VCO_NUMER_GET(x)	(((x) & 0x0000fff8) >> 3)
#define CLKMGR_MAINPLLGRP_L4SRC_L4SP_GET(x)	(((x) & 0x00000002) >> 1)
#define CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_GET(x)  (((x) & 0x00000380) >> 7)
#define CLKMGR_SDRPLLGRP_VCO_SSRC_GET(x)	(((x) & 0x00c00000) >> 22)
#define CLKMGR_SDRPLLGRP_VCO_DENOM_GET(x)	(((x) & 0x003f0000) >> 16)
#define CLKMGR_SDRPLLGRP_VCO_NUMER_GET(x)	(((x) & 0x0000fff8) >> 3)
#define CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_GET(x)	(((x) & 0x000001ff) >> 0)
#define CLKMGR_PERPLLGRP_VCO_SSRC_GET(x)	(((x) & 0x00c00000) >> 22)
#define CLKMGR_PERPLLGRP_VCO_DENOM_GET(x)	(((x) & 0x003f0000) >> 16)
#define CLKMGR_PERPLLGRP_VCO_NUMER_GET(x)	(((x) & 0x0000fff8) >> 3)
#define CLKMGR_PERPLLGRP_SRC_QSPI_GET(x)	(((x) & 0x00000030) >> 4)
#define CLKMGR_PERPLLGRP_SRC_SDMMC_GET(x)	(((x) & 0x00000003) >> 0)

#define CLKMGR_VCO_SSRC_EOSC1		0x0
#define CLKMGR_VCO_SSRC_EOSC2		0x1
#define CLKMGR_VCO_SSRC_F2S		0x2
#define CLKMGR_L4_SP_CLK_SRC_MAINPLL	0x0
#define CLKMGR_L4_SP_CLK_SRC_PERPLL	0x1
#define CLKMGR_SDMMC_CLK_SRC_F2S	0x0
#define CLKMGR_SDMMC_CLK_SRC_MAIN	0x1
#define CLKMGR_SDMMC_CLK_SRC_PER	0x2
#define CLKMGR_QSPI_CLK_SRC_F2S		0x0
#define CLKMGR_QSPI_CLK_SRC_MAIN	0x1
#define CLKMGR_QSPI_CLK_SRC_PER		0x2

#ifndef __ASSEMBLY__
/* global variable which consume by drivers */
extern unsigned long cm_l4_sp_clock __attribute__((section(".data")));
extern unsigned long cm_sdmmc_clock __attribute__((section(".data")));
extern unsigned long cm_qspi_clock __attribute__((section(".data")));
#endif /* __ASSEMBLY__ */

/* Bypass Main and Per PLL, bypass source per input mux */
#define CLKMGR_BYPASS_MAIN_PER_PLL_MASK		0x19

#define CLKMGR_MAINQSPICLK_RESET_VALUE		0x3
#define CLKMGR_MAINNANDSDMMCCLK_RESET_VALUE	0x3
#define CLKMGR_PERQSPICLK_RESET_VALUE		0x1
#define CLKMGR_PERNANDSDMMCCLK_RESET_VALUE	0x1

/* Bit masks for dbctrl register */
#define CLKMGR_DBCTRL_ENSFMDWR_MASK 0x00000002
#define CLKMGR_DBCTRL_STAYOSC1_MASK 0x00000001


#endif /* _CLOCK_MANAGER_H_ */
