/*****************************************************************************
* Copyright 2003 - 2008 Broadcom Corporation.  All rights reserved.
*
* Unless you and Broadcom execute a separate written software license
* agreement governing use of this software, this software is licensed to you
* under the terms of the GNU General Public License version 2, available at
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
*
* Notwithstanding the above, under no circumstances may you combine this
* software in any way with any other Broadcom software provided under a
* license other than the GPL, without Broadcom's express prior written
* consent.
*****************************************************************************/

/****************************************************************************/
/**
*  @file    reg.h
*
*  @brief   Generic register definitions used in CSP
*/
/****************************************************************************/

#ifndef CSP_REG_H
#define CSP_REG_H

/* ---- Include Files ---------------------------------------------------- */

#include <csp/stdint.h>

/* ---- Public Constants and Types --------------------------------------- */

#define __REG32(x)      (*((volatile uint32_t *)(x)))
#define __REG16(x)      (*((volatile uint16_t *)(x)))
#define __REG8(x)       (*((volatile uint8_t *) (x)))

/* Macros used to define a sequence of reserved registers. The start / end */
/* are byte offsets in the particular register definition, with the "end" */
/* being the offset of the next un-reserved register. E.g. if offsets */
/* 0x10 through to 0x1f are reserved, then this reserved area could be */
/* specified as follows. */
/*  typedef struct */
/*  { */
/*      uint32_t reg1;           offset 0x00 */
/*      uint32_t reg2;           offset 0x04 */
/*      uint32_t reg3;           offset 0x08 */
/*      uint32_t reg4;           offset 0x0c */
/*      REG32_RSVD(0x10, 0x20); */
/*      uint32_t reg5;           offset 0x20 */
/*      ... */
/*  } EXAMPLE_REG_t; */
#define REG8_RSVD(start, end)   uint8_t rsvd_##start[(end - start) / sizeof(uint8_t)]
#define REG16_RSVD(start, end)  uint16_t rsvd_##start[(end - start) / sizeof(uint16_t)]
#define REG32_RSVD(start, end)  uint32_t rsvd_##start[(end - start) / sizeof(uint32_t)]

/* ---- Public Variable Externs ------------------------------------------ */
/* ---- Public Function Prototypes --------------------------------------- */

/* Note: When protecting multiple statements, the REG_LOCAL_IRQ_SAVE and */
/* REG_LOCAL_IRQ_RESTORE must be enclosed in { } to allow the  */
/* flags variable to be declared locally. */
/* e.g. */
/*    statement1; */
/*    { */
/*       REG_LOCAL_IRQ_SAVE; */
/*       <multiple statements here> */
/*       REG_LOCAL_IRQ_RESTORE; */
/*    } */
/*    statement2; */
/*  */

#if defined(__KERNEL__) && !defined(STANDALONE)
#include <mach/hardware.h>
#include <linux/interrupt.h>

#define REG_LOCAL_IRQ_SAVE      HW_DECLARE_SPINLOCK(reg32) \
	unsigned long flags; HW_IRQ_SAVE(reg32, flags)

#define REG_LOCAL_IRQ_RESTORE   HW_IRQ_RESTORE(reg32, flags)

#else

#define REG_LOCAL_IRQ_SAVE
#define REG_LOCAL_IRQ_RESTORE

#endif

static inline void reg32_modify_and(volatile uint32_t *reg, uint32_t value)
{
	REG_LOCAL_IRQ_SAVE;
	*reg &= value;
	REG_LOCAL_IRQ_RESTORE;
}

static inline void reg32_modify_or(volatile uint32_t *reg, uint32_t value)
{
	REG_LOCAL_IRQ_SAVE;
	*reg |= value;
	REG_LOCAL_IRQ_RESTORE;
}

static inline void reg32_modify_mask(volatile uint32_t *reg, uint32_t mask,
				     uint32_t value)
{
	REG_LOCAL_IRQ_SAVE;
	*reg = (*reg & mask) | value;
	REG_LOCAL_IRQ_RESTORE;
}

static inline void reg32_write(volatile uint32_t *reg, uint32_t value)
{
	*reg = value;
}

#endif /* CSP_REG_H */
