To use these, set things up like this: struct uart_ctlr *uart = (struct uart_ctlr *)UART_PA_START;
#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, }; 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_writel(UART_FBCON, 6, &uart->fbcon) - set the UART's FBCON field to 6 bf_enum_writel(UART_FBCON, MULTI, &uart->fbcon) - set the UART's FBCON field to MULTI Signed-off-by: Simon Glass <s...@chromium.org> --- arch/arm/include/asm/arch-tegra2/bitfield.h | 151 ++++++++++++++++++ test/Makefile | 36 ++++ test/bitfield.c | 230 +++++++++++++++++++++++++++ 3 files changed, 417 insertions(+), 0 deletions(-) create mode 100644 arch/arm/include/asm/arch-tegra2/bitfield.h create mode 100644 test/Makefile create mode 100644 test/bitfield.c diff --git a/arch/arm/include/asm/arch-tegra2/bitfield.h b/arch/arm/include/asm/arch-tegra2/bitfield.h new file mode 100644 index 0000000..6a1bbfa --- /dev/null +++ b/arch/arm/include/asm/arch-tegra2/bitfield.h @@ -0,0 +1,151 @@ +/* + * 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_writel(field, _enum, reg) \ + bf_writel(field, field ## _ ## _enum, reg) + +#endif diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..6d8c6a7 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,36 @@ +# 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 + +TESTS=bitfield + +INC=../arch/arm/include/asm/arch-tegra2 +CFLAGS=-DDEBUG -I$(INC) + +all: tests run + +tests: $(TESTS) + +bitfield: bitfield.o + +bitfield.o: $(INC)/bitfield.h + +run: + @echo "Running tests $(TESTS)" + @./bitfield + @echo "Tests completed." diff --git a/test/bitfield.c b/test/bitfield.c new file mode 100644 index 0000000..5fc381d --- /dev/null +++ b/test/bitfield.c @@ -0,0 +1,230 @@ +/* + * 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 + */ + +/* + * Bitfield test routines + * + */ + +#include <stdio.h> + +#include "bitfield.h" + + +#define FULL_RANGE 31 : 0 +#define HIGH_RANGE 31 : 30 +#define MID_RANGE 23 : 16 +#define LOW_RANGE 2 : 0 +#define HIGH_SINGLE_RANGE 31 : 31 +#define MID_SINGLE_RANGE 16 : 16 +#define LOW_SINGLE_RANGE 0 : 0 + +static int test_count; + +#ifdef DEBUG +#define assert(x) \ + ({ test_count++; \ + if (!(x)) \ + printf("Assertion failure '%s' %s line %d\n", \ + #x, __FILE__, __LINE__) }) +#define asserteq(x, y) \ + ({ int _x = x; int _y = y; test_count++; \ + if (_x != _y) \ + printf("Assertion failure at %s:%d: '%s' %#x != '%s' %#x\n", \ + __FILE__, __LINE__, #x, _x, #y, _y); }) +#else +#define assert(x) (test_count++) +#define asserteq(x, y) (test_count++) +#endif + + +static void test_low_high(void) +{ + asserteq(BITFIELD_HIGHBIT(FULL_RANGE), 31); + asserteq(BITFIELD_LOWBIT(FULL_RANGE), 0); + asserteq(BITFIELD_HIGHBIT(HIGH_RANGE), 31); + asserteq(BITFIELD_LOWBIT(HIGH_RANGE), 30); + asserteq(BITFIELD_HIGHBIT(MID_RANGE), 23); + asserteq(BITFIELD_LOWBIT(MID_RANGE), 16); + asserteq(BITFIELD_HIGHBIT(LOW_RANGE), 2); + asserteq(BITFIELD_LOWBIT(LOW_RANGE), 0); + asserteq(BITFIELD_HIGHBIT(HIGH_SINGLE_RANGE), 31); + asserteq(BITFIELD_LOWBIT(HIGH_SINGLE_RANGE), 31); + asserteq(BITFIELD_HIGHBIT(MID_SINGLE_RANGE), 16); + asserteq(BITFIELD_LOWBIT(MID_SINGLE_RANGE), 16); + asserteq(BITFIELD_HIGHBIT(LOW_SINGLE_RANGE), 0); + asserteq(BITFIELD_LOWBIT(LOW_SINGLE_RANGE), 0); +} + +static void test_width(void) +{ + asserteq(BITFIELD_WIDTH(FULL_RANGE), 32); + asserteq(BITFIELD_WIDTH(HIGH_RANGE), 2); + asserteq(BITFIELD_WIDTH(MID_RANGE), 8); + asserteq(BITFIELD_WIDTH(LOW_RANGE), 3); + asserteq(BITFIELD_WIDTH(HIGH_SINGLE_RANGE), 1); + asserteq(BITFIELD_WIDTH(MID_SINGLE_RANGE), 1); + asserteq(BITFIELD_WIDTH(LOW_SINGLE_RANGE), 1); +} + +static void test_shift(void) +{ + asserteq(bf_shift(FULL), 0); + asserteq(bf_shift(HIGH), 30); + asserteq(bf_shift(MID), 16); + asserteq(bf_shift(LOW), 0); + asserteq(bf_shift(HIGH_SINGLE), 31); + asserteq(bf_shift(MID_SINGLE), 16); + asserteq(bf_shift(LOW_SINGLE), 0); +} + +static void test_rawmask(void) +{ + asserteq(bf_rawmask(FULL), 0xffffffffU); + asserteq(bf_rawmask(HIGH), 0x3); + asserteq(bf_rawmask(MID), 0xff); + asserteq(bf_rawmask(LOW), 0x7); + asserteq(bf_rawmask(HIGH_SINGLE), 0x1); + asserteq(bf_rawmask(MID_SINGLE), 0x1); + asserteq(bf_rawmask(LOW_SINGLE), 0x1); +} + +static void test_mask(void) +{ + asserteq(bf_mask(FULL), 0xffffffffU); + asserteq(bf_mask(HIGH), 0xc0000000); + asserteq(bf_mask(MID), 0x00ff0000); + asserteq(bf_mask(LOW), 0x7); + asserteq(bf_mask(HIGH_SINGLE), 0x80000000U); + asserteq(bf_mask(MID_SINGLE), 0x00010000); + asserteq(bf_mask(LOW_SINGLE), 0x1); +} + +static void test_unpack(void) +{ + asserteq(bf_unpack(FULL, 0), 0); + asserteq(bf_unpack(FULL, -1U), -1U); + asserteq(bf_unpack(FULL, 0x12345678), 0x12345678); + asserteq(bf_unpack(FULL, 0x87654321), 0x87654321); + asserteq(bf_unpack(FULL, 0xa5a5a5a6), 0xa5a5a5a6); + + asserteq(bf_unpack(HIGH, 0), 0); + asserteq(bf_unpack(HIGH, -1U), 3); + asserteq(bf_unpack(HIGH, 0x12345678), 0); + asserteq(bf_unpack(HIGH, 0x87654321), 2); + asserteq(bf_unpack(HIGH, 0xa5a5a5a6), 2); + + asserteq(bf_unpack(MID, 0), 0); + asserteq(bf_unpack(MID, -1U), 0xff); + asserteq(bf_unpack(MID, 0x12345678), 0x34); + asserteq(bf_unpack(MID, 0x87654321), 0x65); + asserteq(bf_unpack(MID, 0xa5a5a5a6), 0xa5); + + asserteq(bf_unpack(LOW, 0), 0); + asserteq(bf_unpack(LOW, -1U), 7); + asserteq(bf_unpack(LOW, 0x12345678), 0); + asserteq(bf_unpack(LOW, 0x87654321), 1); + asserteq(bf_unpack(LOW, 0xa5a5a5a6), 6); + + asserteq(bf_unpack(HIGH_SINGLE, 0), 0); + asserteq(bf_unpack(HIGH_SINGLE, -1U), 1); + asserteq(bf_unpack(HIGH_SINGLE, 0x12345678), 0); + asserteq(bf_unpack(HIGH_SINGLE, 0x87654321), 1); + asserteq(bf_unpack(HIGH_SINGLE, 0xa5a5a5a6), 1); + + asserteq(bf_unpack(MID_SINGLE, 0), 0); + asserteq(bf_unpack(MID_SINGLE, -1U), 1); + asserteq(bf_unpack(MID_SINGLE, 0x12345678), 0); + asserteq(bf_unpack(MID_SINGLE, 0x87654321), 1); + asserteq(bf_unpack(MID_SINGLE, 0xa5a5a5a6), 1); + + asserteq(bf_unpack(LOW_SINGLE, 0), 0); + asserteq(bf_unpack(LOW_SINGLE, -1U), 1); + asserteq(bf_unpack(LOW_SINGLE, 0x12345678), 0); + asserteq(bf_unpack(LOW_SINGLE, 0x87654321), 1); + asserteq(bf_unpack(LOW_SINGLE, 0xa5a5a5a6), 0); +} + +static void test_pack(void) +{ + asserteq(bf_pack(FULL, 0), 0); + asserteq(bf_pack(FULL, -1U), -1U); + asserteq(bf_pack(FULL, 0x12345678), 0x12345678); + asserteq(bf_pack(FULL, 0x87654321), 0x87654321); + asserteq(bf_pack(FULL, 0xa5a5a5a6), 0xa5a5a5a6); + + asserteq(bf_pack(HIGH, 0), 0); + asserteq(bf_pack(HIGH, -1U), 0xc0000000); + asserteq(bf_pack(HIGH, 0x12345678), 0); + asserteq(bf_pack(HIGH, 0x87654321), 0x40000000); + asserteq(bf_pack(HIGH, 0xa5a5a5a6), 0x80000000); + + asserteq(bf_pack(MID, 0), 0); + asserteq(bf_pack(MID, -1U), 0x00ff0000); + asserteq(bf_pack(MID, 0x12345678), 0x00780000); + asserteq(bf_pack(MID, 0x87654321), 0x00210000); + asserteq(bf_pack(MID, 0xa5a5a5a6), 0x00a60000); + + asserteq(bf_pack(LOW, 0), 0); + asserteq(bf_pack(LOW, -1U), 7); + asserteq(bf_pack(LOW, 0x12345678), 0); + asserteq(bf_pack(LOW, 0x87654321), 1); + asserteq(bf_pack(LOW, 0xa5a5a5a6), 6); + + asserteq(bf_pack(HIGH_SINGLE, 0), 0); + asserteq(bf_pack(HIGH_SINGLE, -1U), 0x80000000u); + asserteq(bf_pack(HIGH_SINGLE, 0x12345678), 0); + asserteq(bf_pack(HIGH_SINGLE, 0x87654321), 0x80000000u); + asserteq(bf_pack(HIGH_SINGLE, 0xa5a5a5a6), 0x00000000u); + + asserteq(bf_pack(MID_SINGLE, 0), 0); + asserteq(bf_pack(MID_SINGLE, -1U), 0x00010000); + asserteq(bf_pack(MID_SINGLE, 0x12345678), 0); + asserteq(bf_pack(MID_SINGLE, 0x87654321), 0x00010000); + asserteq(bf_pack(MID_SINGLE, 0xa5a5a5a6), 0x00000000); + + asserteq(bf_pack(LOW_SINGLE, 0), 0); + asserteq(bf_pack(LOW_SINGLE, -1U), 1); + asserteq(bf_pack(LOW_SINGLE, 0x12345678), 0); + asserteq(bf_pack(LOW_SINGLE, 0x87654321), 1); + asserteq(bf_pack(LOW_SINGLE, 0xa5a5a5a6), 0); +} + +static void test_set(void) +{ +} + +void bf_test(void) +{ + test_low_high(); + test_width(); + test_shift(); + test_rawmask(); + test_unpack(); + test_pack(); +} + +int main(int argc, char *argv[]) +{ + bf_test(); + printf("%d tests run\n", test_count); + return 0; +} -- 1.7.3.1 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot