diff options
author | Ken Adams <kadams@nvidia.com> | 2015-07-07 09:26:19 -0400 |
---|---|---|
committer | Alexandre Courbot <acourbot@nvidia.com> | 2015-11-10 16:42:20 +0900 |
commit | 819e066c88cf0bfb5e00ec4f76563e8dddeef959 (patch) | |
tree | 13efd7738d4c91558fdc7083698b7cedece0d615 | |
parent | 0d97f256240426be4dfc318d2d35c3ea2d1c659a (diff) | |
download | nouveau-819e066c88cf0bfb5e00ec4f76563e8dddeef959.tar.gz |
hwref: usage macros and docs
Included is a scheme to reference the hwref definitions
which NVIDA uses internally called the "drf def" system.
Signed-off-by: Ken Adams <kadams@nvidia.com>
-rw-r--r-- | drm/nouveau/include/nvkm/hwref/nv_drf.h | 88 | ||||
-rw-r--r-- | drm/nouveau/include/nvkm/hwref/nv_drf.txt | 123 |
2 files changed, 211 insertions, 0 deletions
diff --git a/drm/nouveau/include/nvkm/hwref/nv_drf.h b/drm/nouveau/include/nvkm/hwref/nv_drf.h new file mode 100644 index 000000000..1f3433e37 --- /dev/null +++ b/drm/nouveau/include/nvkm/hwref/nv_drf.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef __nv_drf_h__ +#define __nv_drf_h__ +/* + * See nv_drf.txt in this directory for explanation/illustrations. + * Note: that discussion isn't necessarily implemented 1:1 here. + */ + +/* + * The following inlines bind the drf macros following to specific integral types. + * They also help provide "is-using" and "can-reach" breadcrumbs for analysis. + */ +static inline u32 _nv_drf_fld_lo_bit(const char *D, const char *R, const char *F, u32 b) +{ + return b; +} +static inline u32 _nv_drf_fld_hi_bit(const char *D, const char *R, const char *F, u32 b) +{ + return b; +} +static inline u32 _nv_drf_fld_val(const char *D, const char *R, const char *F, const char *V, u32 v) +{ + return v; +} +static inline u32 _nv_drf_reg_offset(const char *D, const char *R, u32 o) +{ + return o; +} + +/* return the hi/lo bit numbers for a field */ +#define drf_fld_lo_bit(d,r,f) _nv_drf_fld_lo_bit(#d,#r,#f, 0 ? NV_##d##_##r##_##f) +#define drf_fld_hi_bit(d,r,f) _nv_drf_fld_hi_bit(#d,#r,#f, 1 ? NV_##d##_##r##_##f) + +/* return the bit width and offsets for a field */ +#define drf_fld_width_bits(d,r,f) (1 + drf_fld_hi_bit(d,r,f) - drf_fld_lo_bit(d,r,f)) +#define drf_fld_shift_bits(d,r,f) drf_fld_lo_bit(d,r,f) + +/* return masks for a field */ +#define drf_fld_mask(d,r,f) ((1 << drf_fld_width_bits(d,r,f)) - 1) +#define drf_fld_mask_placed(d,r,f) (drf_fld_mask(d,r,f) << drf_fld_shift_bits(d,r,f)) + +/* return defined values for a field */ +#define drf_fld_val(d,r,f,v) _nv_drf_fld_val(#d,#r,#f,#v, NV_##d##_##r##_##f##_##v) +#define drf_fld_val_placed(d,r,f,v) (drf_fld_val(d,r,f,v) << drf_fld_shift_bits(d,r,f)) + +/* mask off a number for use in a field */ +#define drf_fld_num(d,r,f,n) ((n) & drf_fld_mask(d,r,f)) +#define drf_fld_num_placed(d,r,f,n) (drf_fld_num(d,r,f,n) << drf_fld_shift_bits(d,r,f)) + +/* return the value of a field within a given */ +#define drf_get_fld(g, d,r,f) (((g) >> drf_fld_shift_bits(d,r,f)) & drf_fld_mask(d,r,f) ) +#define drf_get_fld_placed(g, d,r,f) ((g) & drf_fld_mask_placed(d,r,f)) + +/* utils to clear and set fields within a given */ +#define drf_clear_fld(g, d,r,f) ((g) & ~drf_fld_mask_placed(d,r,f)) +#define drf_set_fld_val(g, d,r,f,v) (drf_clear_fld(g, d,r,f) | drf_fld_val_placed(d,r,f,v)) +#define drf_set_fld_num(g, d,r,f,n) (drf_clear_fld(g, d,r,f) | drf_fld_num_placed(d,r,f,n)) + +/* return register offset */ +#define drf_reg_offset(d,r) _nv_drf_reg_offset(#d,#r,NV_##d##_##r) + +/* register read32 coupled with field ops. note: p == priv given to nv_rd32 */ +#define drf_rd32(p, d,r) nv_rd32(p, drf_reg_offset(d,r)) +#define drf_rd32_fld(p, d,r,f) drf_get_fld(drf_rd32(p, d,r), d,r,f) +#define drf_rd32_fld_placed(p, d,r,f) drf_get_fld_placed(drf_rd32(p, d,r), d,r,f) + +#endif /* __nv_drf_h__ */ diff --git a/drm/nouveau/include/nvkm/hwref/nv_drf.txt b/drm/nouveau/include/nvkm/hwref/nv_drf.txt new file mode 100644 index 000000000..bbfc63f70 --- /dev/null +++ b/drm/nouveau/include/nvkm/hwref/nv_drf.txt @@ -0,0 +1,123 @@ + +For registers, consider a hierarchical naming scheme: + + 'd' -> device/engine + 'r' -> register offset + 'f' -> field hi:lo bits within the register + 'v' -> value for use in the field + +Memory objects can be treated similarly: + + 'd' -> data/struct + 'o' -> byte offset (within the object/struct, or use 'w' for 32b word, etc.) + 'f' -> field hi:lo bits + 'v' -> field value + +To construct names assume the following naming pattern: + + NV_<d> : a range of addresses/offsets + NV_<d>_<r> : a specific register offset + NV_<d>_<r>_<f> : a range of bits + NV_<d>_<r>_<f>_<v> : a specific value for use within a field + +E.g.: + + #define NV_PGRAPH 0x0040FFFF:0x00400000 + #define NV_PGRAPH_STATUS 0x400700 + #define NV_PGRAPH_STATUS_STATE 0:0 + #define NV_PGRAPH_STATUS_STATE_BUSY 1 + +To refer to a specific register, say, create a macro to take the +'d' and 'r' as parameters and construct the appropriate name using +token concatenation: + + #define NV_DRF_REG(d, r) NV_ ## d ## _ ## r + +Invocation would be: NV_DRF_REG(PGRAPH, STATUS) for the NV_PGRAPH_STATUS +register above. + +For fields (bit locations), append 'f'. + + #define NV_DRF_FIELD(d, r, f) NV_ ## d ## _ ## r ## _ ## f + +For specific field value enumerants add 'v': + + #define NV_DRF_FIELD_VAL(d, r, f, v) NV_ ## d ## _ ## r ## _ ## f ## _ ## v + +To refer to the high part of a range (here, a bit field) use a +conditional ternary as follows: ( <0|1> ? <hi> : <lo> ) + + #define NV_DRF_FIELD_HI(d, r, f) ( 1 ? NV_DRF_FIELD(d, r, f) ) + #define NV_DRF_FIELD_LO(d, r, f) ( 0 ? NV_DRF_FIELD(d, r, f) ) + +The example below shows how we arrive at the high and low bit numbers. + + #define NV_PGRAPH_FOO_BAR 2:1 + +NV_DRF_FIELD_HI(PGRAPH,FOO,BAR) expands to ( 1 ? 2:1 ) -> 2 +NV_DRF_FIELD_LO(PGRAPH,FOO,BAR) expands to ( 0 ? 2:1 ) -> 1 + +From these we can create various macros for managing the bits within fields: +placing field values, extracting them, masking them, etc. + +A specific field's value can be thought of in two ways: + . "in-place" + . or as a "value" (or number) shifted to the bit-0 position. + +The latter is suitable for math ops, etc. The first is suitable for +or-ing with other fields within the register. + +We say "get field" to name the operation which extracts and shifts the +appropriate bits to bit zero. We say "set field" to name the operation +which takes a value, masks it and then shifts it to the field's position. + +Field enumerants are treated as a special case of "set" which appends a +"V" position to the token pasting. Illustrated (see below for drf_* macro +definitions): + + #define D 0x100:0x0 // the example "device" + #define D_R 0x20 // a "register" + #define D_R_F 5:1 // a "field" + #define D_R_F_FOO 0 // a field value + #define D_R_F_BAR 1 // "" + #define D_R_F_BAZ 9 // "" + + expanding drf_setv(D, R, F, BAZ) we get: + + drf_set(D,R,F, D_R_F_BAZ) -> + drf_set(D,R,F, 9) -> + (9 & drf_mask(D, R, F)) << drf_shift(D,R,F) -> + (9 & (~0 >> 31-drf_width(D, R, F))) << drf_lo(D,R,F) -> + (9 & (~0 >> 31-(1+drf_hi(D,R,F)-drf_lo(D,R,F)))) << drf_lo(D,R,F) -> + (9 & (~0 >> 31-(1+(1?D_R_F) - (0?D_R_F)))) << (0?D_R_F) -> + (9 & (~0 >> 31-(1+(1?5:1) - (0?5:1)))) << (0?5:1) -> + (9 & (~0 >> 31-(1+ (5) - (1)))) << (1) -> + (9 & (~0 >> 31-(1+5-1))) << (1) -> + (9 & (0xffffffff >> (31-5))) << 1 -> + (9 & (0xffffffff >> 26)) << 1 -> + (9 & 0x1f) << 1 -> + 9 << 1 -> + 0x12 + +Note that the above collapses neatly at compile time. That's a feature. + +An important thing to note is that values "in-place" are suitable for bit-wise +oring (|) to accumulate multiple fields for use in the same register. To extend +the previous example: + #define D_R_FTOO 6:6 // a second 1-bit wide "field" + #define D_R_FTOO_ENABLED 1 + #define D_R_FTOO_DISABLED 0 + +The following would be correct usage to form a new register value for +the example register "D_R": + drf_setv(D,R, F, BAZ) | drf_setv(D,R, FTOO, ENABLED) + +The following illustrates the reverse, inspecting values on a per-field +basis: + u32 d_r = read_reg(drf_r(D, R)); + + if ( drf_get(D, R, FTOO, d_r) == drf_v(D, R, FTOO, ENABLED) ) { + cout << "the FTOO value of register d_r is _ENABLED"; + } + + |