summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKen Adams <kadams@nvidia.com>2015-07-07 09:26:19 -0400
committerAlexandre Courbot <acourbot@nvidia.com>2015-11-10 16:42:20 +0900
commit819e066c88cf0bfb5e00ec4f76563e8dddeef959 (patch)
tree13efd7738d4c91558fdc7083698b7cedece0d615
parent0d97f256240426be4dfc318d2d35c3ea2d1c659a (diff)
downloadnouveau-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.h88
-rw-r--r--drm/nouveau/include/nvkm/hwref/nv_drf.txt123
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";
+ }
+
+