linux/drivers/gpu/drm/amd/display/dc/calcs/custom_float.c
<<
>>
Prefs
   1/*
   2 * Copyright 2017 Advanced Micro Devices, Inc.
   3 *
   4 * Permission is hereby granted, free of charge, to any person obtaining a
   5 * copy of this software and associated documentation files (the "Software"),
   6 * to deal in the Software without restriction, including without limitation
   7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   8 * and/or sell copies of the Software, and to permit persons to whom the
   9 * Software is furnished to do so, subject to the following conditions:
  10 *
  11 * The above copyright notice and this permission notice shall be included in
  12 * all copies or substantial portions of the Software.
  13 *
  14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
  17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
  18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  20 * OTHER DEALINGS IN THE SOFTWARE.
  21 *
  22 * Authors: AMD
  23 *
  24 */
  25#include "dm_services.h"
  26#include "custom_float.h"
  27
  28
  29static bool build_custom_float(
  30        struct fixed31_32 value,
  31        const struct custom_float_format *format,
  32        bool *negative,
  33        uint32_t *mantissa,
  34        uint32_t *exponenta)
  35{
  36        uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1;
  37
  38        const struct fixed31_32 mantissa_constant_plus_max_fraction =
  39                dc_fixpt_from_fraction(
  40                        (1LL << (format->mantissa_bits + 1)) - 1,
  41                        1LL << format->mantissa_bits);
  42
  43        struct fixed31_32 mantiss;
  44
  45        if (dc_fixpt_eq(
  46                value,
  47                dc_fixpt_zero)) {
  48                *negative = false;
  49                *mantissa = 0;
  50                *exponenta = 0;
  51                return true;
  52        }
  53
  54        if (dc_fixpt_lt(
  55                value,
  56                dc_fixpt_zero)) {
  57                *negative = format->sign;
  58                value = dc_fixpt_neg(value);
  59        } else {
  60                *negative = false;
  61        }
  62
  63        if (dc_fixpt_lt(
  64                value,
  65                dc_fixpt_one)) {
  66                uint32_t i = 1;
  67
  68                do {
  69                        value = dc_fixpt_shl(value, 1);
  70                        ++i;
  71                } while (dc_fixpt_lt(
  72                        value,
  73                        dc_fixpt_one));
  74
  75                --i;
  76
  77                if (exp_offset <= i) {
  78                        *mantissa = 0;
  79                        *exponenta = 0;
  80                        return true;
  81                }
  82
  83                *exponenta = exp_offset - i;
  84        } else if (dc_fixpt_le(
  85                mantissa_constant_plus_max_fraction,
  86                value)) {
  87                uint32_t i = 1;
  88
  89                do {
  90                        value = dc_fixpt_shr(value, 1);
  91                        ++i;
  92                } while (dc_fixpt_lt(
  93                        mantissa_constant_plus_max_fraction,
  94                        value));
  95
  96                *exponenta = exp_offset + i - 1;
  97        } else {
  98                *exponenta = exp_offset;
  99        }
 100
 101        mantiss = dc_fixpt_sub(
 102                value,
 103                dc_fixpt_one);
 104
 105        if (dc_fixpt_lt(
 106                        mantiss,
 107                        dc_fixpt_zero) ||
 108                dc_fixpt_lt(
 109                        dc_fixpt_one,
 110                        mantiss))
 111                mantiss = dc_fixpt_zero;
 112        else
 113                mantiss = dc_fixpt_shl(
 114                        mantiss,
 115                        format->mantissa_bits);
 116
 117        *mantissa = dc_fixpt_floor(mantiss);
 118
 119        return true;
 120}
 121
 122static bool setup_custom_float(
 123        const struct custom_float_format *format,
 124        bool negative,
 125        uint32_t mantissa,
 126        uint32_t exponenta,
 127        uint32_t *result)
 128{
 129        uint32_t i = 0;
 130        uint32_t j = 0;
 131
 132        uint32_t value = 0;
 133
 134        /* verification code:
 135         * once calculation is ok we can remove it
 136         */
 137
 138        const uint32_t mantissa_mask =
 139                (1 << (format->mantissa_bits + 1)) - 1;
 140
 141        const uint32_t exponenta_mask =
 142                (1 << (format->exponenta_bits + 1)) - 1;
 143
 144        if (mantissa & ~mantissa_mask) {
 145                BREAK_TO_DEBUGGER();
 146                mantissa = mantissa_mask;
 147        }
 148
 149        if (exponenta & ~exponenta_mask) {
 150                BREAK_TO_DEBUGGER();
 151                exponenta = exponenta_mask;
 152        }
 153
 154        /* end of verification code */
 155
 156        while (i < format->mantissa_bits) {
 157                uint32_t mask = 1 << i;
 158
 159                if (mantissa & mask)
 160                        value |= mask;
 161
 162                ++i;
 163        }
 164
 165        while (j < format->exponenta_bits) {
 166                uint32_t mask = 1 << j;
 167
 168                if (exponenta & mask)
 169                        value |= mask << i;
 170
 171                ++j;
 172        }
 173
 174        if (negative && format->sign)
 175                value |= 1 << (i + j);
 176
 177        *result = value;
 178
 179        return true;
 180}
 181
 182bool convert_to_custom_float_format(
 183        struct fixed31_32 value,
 184        const struct custom_float_format *format,
 185        uint32_t *result)
 186{
 187        uint32_t mantissa;
 188        uint32_t exponenta;
 189        bool negative;
 190
 191        return build_custom_float(
 192                value, format, &negative, &mantissa, &exponenta) &&
 193        setup_custom_float(
 194                format, negative, mantissa, exponenta, result);
 195}
 196
 197
 198