linux/drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.c
<<
>>
Prefs
   1/*
   2 * Copyright 2012-15 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
  26#include "dm_services.h"
  27#include "include/gpio_types.h"
  28#include "hw_gpio.h"
  29
  30#include "reg_helper.h"
  31#include "gpio_regs.h"
  32
  33#undef FN
  34#define FN(reg_name, field_name) \
  35        gpio->regs->field_name ## _shift, gpio->regs->field_name ## _mask
  36
  37#define CTX \
  38        gpio->base.ctx
  39#define REG(reg)\
  40        (gpio->regs->reg)
  41
  42static void store_registers(
  43        struct hw_gpio *gpio)
  44{
  45        REG_GET(MASK_reg, MASK, &gpio->store.mask);
  46        REG_GET(A_reg, A, &gpio->store.a);
  47        REG_GET(EN_reg, EN, &gpio->store.en);
  48        /* TODO store GPIO_MUX_CONTROL if we ever use it */
  49}
  50
  51static void restore_registers(
  52        struct hw_gpio *gpio)
  53{
  54        REG_UPDATE(MASK_reg, MASK, gpio->store.mask);
  55        REG_UPDATE(A_reg, A, gpio->store.a);
  56        REG_UPDATE(EN_reg, EN, gpio->store.en);
  57        /* TODO restore GPIO_MUX_CONTROL if we ever use it */
  58}
  59
  60bool dal_hw_gpio_open(
  61        struct hw_gpio_pin *ptr,
  62        enum gpio_mode mode)
  63{
  64        struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
  65
  66        store_registers(pin);
  67
  68        ptr->opened = (dal_hw_gpio_config_mode(pin, mode) == GPIO_RESULT_OK);
  69
  70        return ptr->opened;
  71}
  72
  73enum gpio_result dal_hw_gpio_get_value(
  74        const struct hw_gpio_pin *ptr,
  75        uint32_t *value)
  76{
  77        const struct hw_gpio *gpio = FROM_HW_GPIO_PIN(ptr);
  78
  79        enum gpio_result result = GPIO_RESULT_OK;
  80
  81        switch (ptr->mode) {
  82        case GPIO_MODE_INPUT:
  83        case GPIO_MODE_OUTPUT:
  84        case GPIO_MODE_HARDWARE:
  85        case GPIO_MODE_FAST_OUTPUT:
  86                REG_GET(Y_reg, Y, value);
  87                break;
  88        default:
  89                result = GPIO_RESULT_NON_SPECIFIC_ERROR;
  90        }
  91
  92        return result;
  93}
  94
  95enum gpio_result dal_hw_gpio_set_value(
  96        const struct hw_gpio_pin *ptr,
  97        uint32_t value)
  98{
  99        struct hw_gpio *gpio = FROM_HW_GPIO_PIN(ptr);
 100
 101        /* This is the public interface
 102         * where the input comes from client, not shifted yet
 103         * (because client does not know the shifts). */
 104
 105        switch (ptr->mode) {
 106        case GPIO_MODE_OUTPUT:
 107                REG_UPDATE(A_reg, A, value);
 108                return GPIO_RESULT_OK;
 109        case GPIO_MODE_FAST_OUTPUT:
 110                /* We use (EN) to faster switch (used in DDC GPIO).
 111                 * So (A) is grounded, output is driven by (EN = 0)
 112                 * to pull the line down (output == 0) and (EN=1)
 113                 * then output is tri-state */
 114                REG_UPDATE(EN_reg, EN, ~value);
 115                return GPIO_RESULT_OK;
 116        default:
 117                return GPIO_RESULT_NON_SPECIFIC_ERROR;
 118        }
 119}
 120
 121enum gpio_result dal_hw_gpio_change_mode(
 122        struct hw_gpio_pin *ptr,
 123        enum gpio_mode mode)
 124{
 125        struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
 126
 127        return dal_hw_gpio_config_mode(pin, mode);
 128}
 129
 130void dal_hw_gpio_close(
 131        struct hw_gpio_pin *ptr)
 132{
 133        struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
 134
 135        restore_registers(pin);
 136
 137        ptr->mode = GPIO_MODE_UNKNOWN;
 138        ptr->opened = false;
 139}
 140
 141enum gpio_result dal_hw_gpio_config_mode(
 142        struct hw_gpio *gpio,
 143        enum gpio_mode mode)
 144{
 145        gpio->base.mode = mode;
 146
 147        switch (mode) {
 148        case GPIO_MODE_INPUT:
 149                /* turn off output enable, act as input pin;
 150                 * program the pin as GPIO, mask out signal driven by HW */
 151                REG_UPDATE(EN_reg, EN, 0);
 152                REG_UPDATE(MASK_reg, MASK, 1);
 153                return GPIO_RESULT_OK;
 154        case GPIO_MODE_OUTPUT:
 155                /* turn on output enable, act as output pin;
 156                 * program the pin as GPIO, mask out signal driven by HW */
 157                REG_UPDATE(A_reg, A, 0);
 158                REG_UPDATE(MASK_reg, MASK, 1);
 159                return GPIO_RESULT_OK;
 160        case GPIO_MODE_FAST_OUTPUT:
 161                /* grounding the A register then use the EN register bit
 162                 * will have faster effect on the rise time */
 163                REG_UPDATE(A_reg, A, 0);
 164                REG_UPDATE(MASK_reg, MASK, 1);
 165                return GPIO_RESULT_OK;
 166        case GPIO_MODE_HARDWARE:
 167                /* program the pin as tri-state, pin is driven by HW */
 168                REG_UPDATE(MASK_reg, MASK, 0);
 169                return GPIO_RESULT_OK;
 170        case GPIO_MODE_INTERRUPT:
 171                /* Interrupt mode supported only by HPD (IrqGpio) pins. */
 172                REG_UPDATE(MASK_reg, MASK, 0);
 173                return GPIO_RESULT_OK;
 174        default:
 175                return GPIO_RESULT_NON_SPECIFIC_ERROR;
 176        }
 177}
 178
 179void dal_hw_gpio_construct(
 180        struct hw_gpio *pin,
 181        enum gpio_id id,
 182        uint32_t en,
 183        struct dc_context *ctx)
 184{
 185        pin->base.ctx = ctx;
 186        pin->base.id = id;
 187        pin->base.en = en;
 188        pin->base.mode = GPIO_MODE_UNKNOWN;
 189        pin->base.opened = false;
 190
 191        pin->store.mask = 0;
 192        pin->store.a = 0;
 193        pin->store.en = 0;
 194        pin->store.mux = 0;
 195
 196        pin->mux_supported = false;
 197}
 198
 199void dal_hw_gpio_destruct(
 200        struct hw_gpio *pin)
 201{
 202        ASSERT(!pin->base.opened);
 203}
 204