linux/drivers/staging/sm750fb/ddk750_mode.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2
   3#include "ddk750_reg.h"
   4#include "ddk750_mode.h"
   5#include "ddk750_chip.h"
   6
   7/*
   8 * SM750LE only:
   9 * This function takes care extra registers and bit fields required to set
  10 * up a mode in SM750LE
  11 *
  12 * Explanation about Display Control register:
  13 * HW only supports 7 predefined pixel clocks, and clock select is
  14 * in bit 29:27 of Display Control register.
  15 */
  16static unsigned long
  17displayControlAdjust_SM750LE(struct mode_parameter *pModeParam,
  18                             unsigned long dispControl)
  19{
  20        unsigned long x, y;
  21
  22        x = pModeParam->horizontal_display_end;
  23        y = pModeParam->vertical_display_end;
  24
  25        /*
  26         * SM750LE has to set up the top-left and bottom-right
  27         * registers as well.
  28         * Note that normal SM750/SM718 only use those two register for
  29         * auto-centering mode.
  30         */
  31        poke32(CRT_AUTO_CENTERING_TL, 0);
  32
  33        poke32(CRT_AUTO_CENTERING_BR,
  34               (((y - 1) << CRT_AUTO_CENTERING_BR_BOTTOM_SHIFT) &
  35                CRT_AUTO_CENTERING_BR_BOTTOM_MASK) |
  36               ((x - 1) & CRT_AUTO_CENTERING_BR_RIGHT_MASK));
  37
  38        /*
  39         * Assume common fields in dispControl have been properly set before
  40         * calling this function.
  41         * This function only sets the extra fields in dispControl.
  42         */
  43
  44        /* Clear bit 29:27 of display control register */
  45        dispControl &= ~CRT_DISPLAY_CTRL_CLK_MASK;
  46
  47        /* Set bit 29:27 of display control register for the right clock */
  48        /* Note that SM750LE only need to supported 7 resolutions. */
  49        if (x == 800 && y == 600)
  50                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL41;
  51        else if (x == 1024 && y == 768)
  52                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL65;
  53        else if (x == 1152 && y == 864)
  54                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
  55        else if (x == 1280 && y == 768)
  56                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL80;
  57        else if (x == 1280 && y == 720)
  58                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL74;
  59        else if (x == 1280 && y == 960)
  60                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
  61        else if (x == 1280 && y == 1024)
  62                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL108;
  63        else /* default to VGA clock */
  64                dispControl |= CRT_DISPLAY_CTRL_CLK_PLL25;
  65
  66        /* Set bit 25:24 of display controller */
  67        dispControl |= (CRT_DISPLAY_CTRL_CRTSELECT | CRT_DISPLAY_CTRL_RGBBIT);
  68
  69        /* Set bit 14 of display controller */
  70        dispControl |= DISPLAY_CTRL_CLOCK_PHASE;
  71
  72        poke32(CRT_DISPLAY_CTRL, dispControl);
  73
  74        return dispControl;
  75}
  76
  77/* only timing related registers will be  programed */
  78static int programModeRegisters(struct mode_parameter *pModeParam,
  79                                struct pll_value *pll)
  80{
  81        int ret = 0;
  82        int cnt = 0;
  83        unsigned int tmp, reg;
  84
  85        if (pll->clock_type == SECONDARY_PLL) {
  86                /* programe secondary pixel clock */
  87                poke32(CRT_PLL_CTRL, sm750_format_pll_reg(pll));
  88
  89                tmp = ((pModeParam->horizontal_total - 1) <<
  90                       CRT_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
  91                     CRT_HORIZONTAL_TOTAL_TOTAL_MASK;
  92                tmp |= (pModeParam->horizontal_display_end - 1) &
  93                      CRT_HORIZONTAL_TOTAL_DISPLAY_END_MASK;
  94
  95                poke32(CRT_HORIZONTAL_TOTAL, tmp);
  96
  97                tmp = (pModeParam->horizontal_sync_width <<
  98                       CRT_HORIZONTAL_SYNC_WIDTH_SHIFT) &
  99                     CRT_HORIZONTAL_SYNC_WIDTH_MASK;
 100                tmp |= (pModeParam->horizontal_sync_start - 1) &
 101                      CRT_HORIZONTAL_SYNC_START_MASK;
 102
 103                poke32(CRT_HORIZONTAL_SYNC, tmp);
 104
 105                tmp = ((pModeParam->vertical_total - 1) <<
 106                       CRT_VERTICAL_TOTAL_TOTAL_SHIFT) &
 107                     CRT_VERTICAL_TOTAL_TOTAL_MASK;
 108                tmp |= (pModeParam->vertical_display_end - 1) &
 109                      CRT_VERTICAL_TOTAL_DISPLAY_END_MASK;
 110
 111                poke32(CRT_VERTICAL_TOTAL, tmp);
 112
 113                tmp = ((pModeParam->vertical_sync_height <<
 114                       CRT_VERTICAL_SYNC_HEIGHT_SHIFT)) &
 115                     CRT_VERTICAL_SYNC_HEIGHT_MASK;
 116                tmp |= (pModeParam->vertical_sync_start - 1) &
 117                      CRT_VERTICAL_SYNC_START_MASK;
 118
 119                poke32(CRT_VERTICAL_SYNC, tmp);
 120
 121                tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
 122                if (pModeParam->vertical_sync_polarity)
 123                        tmp |= DISPLAY_CTRL_VSYNC_PHASE;
 124                if (pModeParam->horizontal_sync_polarity)
 125                        tmp |= DISPLAY_CTRL_HSYNC_PHASE;
 126
 127                if (sm750_get_chip_type() == SM750LE) {
 128                        displayControlAdjust_SM750LE(pModeParam, tmp);
 129                } else {
 130                        reg = peek32(CRT_DISPLAY_CTRL) &
 131                                ~(DISPLAY_CTRL_VSYNC_PHASE |
 132                                  DISPLAY_CTRL_HSYNC_PHASE |
 133                                  DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE);
 134
 135                        poke32(CRT_DISPLAY_CTRL, tmp | reg);
 136                }
 137
 138        } else if (pll->clock_type == PRIMARY_PLL) {
 139                unsigned int reserved;
 140
 141                poke32(PANEL_PLL_CTRL, sm750_format_pll_reg(pll));
 142
 143                reg = ((pModeParam->horizontal_total - 1) <<
 144                        PANEL_HORIZONTAL_TOTAL_TOTAL_SHIFT) &
 145                        PANEL_HORIZONTAL_TOTAL_TOTAL_MASK;
 146                reg |= ((pModeParam->horizontal_display_end - 1) &
 147                        PANEL_HORIZONTAL_TOTAL_DISPLAY_END_MASK);
 148                poke32(PANEL_HORIZONTAL_TOTAL, reg);
 149
 150                poke32(PANEL_HORIZONTAL_SYNC,
 151                       ((pModeParam->horizontal_sync_width <<
 152                         PANEL_HORIZONTAL_SYNC_WIDTH_SHIFT) &
 153                        PANEL_HORIZONTAL_SYNC_WIDTH_MASK) |
 154                       ((pModeParam->horizontal_sync_start - 1) &
 155                        PANEL_HORIZONTAL_SYNC_START_MASK));
 156
 157                poke32(PANEL_VERTICAL_TOTAL,
 158                       (((pModeParam->vertical_total - 1) <<
 159                         PANEL_VERTICAL_TOTAL_TOTAL_SHIFT) &
 160                        PANEL_VERTICAL_TOTAL_TOTAL_MASK) |
 161                       ((pModeParam->vertical_display_end - 1) &
 162                        PANEL_VERTICAL_TOTAL_DISPLAY_END_MASK));
 163
 164                poke32(PANEL_VERTICAL_SYNC,
 165                       ((pModeParam->vertical_sync_height <<
 166                         PANEL_VERTICAL_SYNC_HEIGHT_SHIFT) &
 167                        PANEL_VERTICAL_SYNC_HEIGHT_MASK) |
 168                       ((pModeParam->vertical_sync_start - 1) &
 169                        PANEL_VERTICAL_SYNC_START_MASK));
 170
 171                tmp = DISPLAY_CTRL_TIMING | DISPLAY_CTRL_PLANE;
 172                if (pModeParam->vertical_sync_polarity)
 173                        tmp |= DISPLAY_CTRL_VSYNC_PHASE;
 174                if (pModeParam->horizontal_sync_polarity)
 175                        tmp |= DISPLAY_CTRL_HSYNC_PHASE;
 176                if (pModeParam->clock_phase_polarity)
 177                        tmp |= DISPLAY_CTRL_CLOCK_PHASE;
 178
 179                reserved = PANEL_DISPLAY_CTRL_RESERVED_MASK |
 180                        PANEL_DISPLAY_CTRL_VSYNC;
 181
 182                reg = (peek32(PANEL_DISPLAY_CTRL) & ~reserved) &
 183                        ~(DISPLAY_CTRL_CLOCK_PHASE | DISPLAY_CTRL_VSYNC_PHASE |
 184                          DISPLAY_CTRL_HSYNC_PHASE | DISPLAY_CTRL_TIMING |
 185                          DISPLAY_CTRL_PLANE);
 186
 187                /*
 188                 * May a hardware bug or just my test chip (not confirmed).
 189                 * PANEL_DISPLAY_CTRL register seems requiring few writes
 190                 * before a value can be successfully written in.
 191                 * Added some masks to mask out the reserved bits.
 192                 * Note: This problem happens by design. The hardware will wait
 193                 *       for the next vertical sync to turn on/off the plane.
 194                 */
 195                poke32(PANEL_DISPLAY_CTRL, tmp | reg);
 196
 197                while ((peek32(PANEL_DISPLAY_CTRL) & ~reserved) !=
 198                        (tmp | reg)) {
 199                        cnt++;
 200                        if (cnt > 1000)
 201                                break;
 202                        poke32(PANEL_DISPLAY_CTRL, tmp | reg);
 203                }
 204        } else {
 205                ret = -1;
 206        }
 207        return ret;
 208}
 209
 210int ddk750_setModeTiming(struct mode_parameter *parm, enum clock_type clock)
 211{
 212        struct pll_value pll;
 213
 214        pll.input_freq = DEFAULT_INPUT_CLOCK;
 215        pll.clock_type = clock;
 216
 217        sm750_calc_pll_value(parm->pixel_clock, &pll);
 218        if (sm750_get_chip_type() == SM750LE) {
 219                /* set graphic mode via IO method */
 220                outb_p(0x88, 0x3d4);
 221                outb_p(0x06, 0x3d5);
 222        }
 223        programModeRegisters(parm, &pll);
 224        return 0;
 225}
 226