/* * Copyright (c) 2011 The Chromium OS Authors. * See file CREDITS for list of people who contributed to this * project. * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ #ifndef __TEGRA2_BITFIELD_H #define __TEGRA2_BITFIELD_H /* * Macros for working with bit fields. To use these, set things up like this: * * #define UART_PA_START 0x67000000 Physical address of UART * #define UART_FBCON_RANGE 5:3 Bit range for the FBCON field * enum { An enum with allowed values * UART_FBCON_OFF, * UART_FBCON_ON, * UART_FBCON_MULTI, * UART_FBCON_SLAVE, * }; * struct uart_ctlr *uart = (struct uart_ctlr *)UART_PA_START; * * This defines a bit field of 3 bits starting at bit 5 and extending down * to bit 3, i.e. 5:3 * * Then: * bf_unpack(UART_FBCON) * - return the value of bits 5:3 (shifted down to bits 2:0) * * bf_pack(UART_FBCON, 4) * - return a word with that field set to 4 (so in this case (4 << 3)) * * bf_update(UART_FBCON, word, val) * - update a field within word so that its value is val. * * bf_enum_writel(UART_FBCON, MULTI, &uart->fbcon) * - set the UART's FBCON field to MULTI * * * Why have bitfield macros? * 1. Reability * 2. Maintainability * 3. Less error prone * * For example, this: * * int RegVal = 0; * RegVal= readl(UsbBase+USB_SUSP_CTRL); * RegVal |= Bit11; * writel(RegVal, UsbBase+USB_SUSP_CTRL); * if(UsbBase == NV_ADDRESS_MAP_USB3_BASE) * { * RegVal = readl(UsbBase+USB_SUSP_CTRL); * RegVal |= Bit12; * writel(RegVal, UsbBase+USB_SUSP_CTRL); * } * * becomes this: * * bitfield_writel(UTMIP_RESET, 1, &usbctlr->susp_ctrl); * if (id == PERIPH_ID_USB3) * bitfield_writel(UTMIP_PHY_ENB, 1, &usbctlr->susp_ctrl); */ /* Returns the low bit of the bitfield */ #define BITFIELD_LOWBIT(range) ((0 ? range) & 0x1f) /* Returns the high bit of the bitfield */ #define BITFIELD_HIGHBIT(range) (1 ? range) /* Returns the width of the bitfield (in bits) */ #define BITFIELD_WIDTH(range) \ (BITFIELD_HIGHBIT(range) - BITFIELD_LOWBIT(range) + 1) /* * Returns the number of bits the bitfield needs to be shifted left to pack it. * This is just the same as the low bit. */ #define bf_shift(field) BITFIELD_LOWBIT(field ## _RANGE) /* Returns the unshifted mask for the field (i.e. LSB of mask is bit 0) */ #define bf_rawmask(field) (0xfffffffful >> \ (32 - BITFIELD_WIDTH(field ## _RANGE))) /* Returns the mask for a field. Clear these bits to zero the field */ #define bf_mask(field) \ (bf_rawmask(field) << (bf_shift(field))) /* Unpacks and returns a value extracted from a field */ #define bf_unpack(field, word) \ (((unsigned)(word) >> bf_shift(field)) & bf_rawmask(field)) /* * Packs a value into a field - this masks the value to ensure it does not * overflow into another field. */ #define bf_pack(field, value) \ ((((unsigned)(value)) & bf_rawmask(field)) \ << bf_shift(field)) /* Sets the value of a field in a word to the given value */ #define bf_update(field, word, value) \ ((word) = ((word) & ~bf_mask(field)) | \ bf_pack(field, value)) /* * Sets the value of a field in a register to the given value using * readl/writel */ #define bf_writel(field, value, reg) ({ \ u32 *__reg = (u32 *)(reg); \ u32 __oldval = readl(__reg); \ bf_update(field, __oldval, value); \ writel(__oldval, __reg); \ }) /* Unpacks a field from a register using readl */ #define bf_readl(field, reg) \ bf_unpack(field, readl(reg)) /* * Clears a field in a register using writel - like * bf_writel(field, 0, reg) */ #define bf_clearl(field, reg) bf_writel(field, 0, reg) /* * Sets the value of a field in a register to the given enum. * * The enum should have the field as a prefix. */ #define bf_enum(field, _enum) bf_pack(field, field ## _ ## _enum) /* * Sets the value of a field in a register to the given enum. * * The enum should have the field as a prefix. */ #define bf_enum_writel(field, _enum, reg) \ bf_writel(field, field ## _ ## _enum, reg) /* * Return a word with the bitfield set to all ones. */ #define bf_ones(field) bf_mask(field) #endif