linux/drivers/gpu/drm/lima/lima_pmu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0 OR MIT
   2/* Copyright 2017-2019 Qiang Yu <yuq825@gmail.com> */
   3
   4#include <linux/iopoll.h>
   5#include <linux/device.h>
   6
   7#include "lima_device.h"
   8#include "lima_pmu.h"
   9#include "lima_regs.h"
  10
  11#define pmu_write(reg, data) writel(data, ip->iomem + reg)
  12#define pmu_read(reg) readl(ip->iomem + reg)
  13
  14static int lima_pmu_wait_cmd(struct lima_ip *ip)
  15{
  16        struct lima_device *dev = ip->dev;
  17        int err;
  18        u32 v;
  19
  20        err = readl_poll_timeout(ip->iomem + LIMA_PMU_INT_RAWSTAT,
  21                                 v, v & LIMA_PMU_INT_CMD_MASK,
  22                                 100, 100000);
  23        if (err) {
  24                dev_err(dev->dev, "timeout wait pmu cmd\n");
  25                return err;
  26        }
  27
  28        pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK);
  29        return 0;
  30}
  31
  32static u32 lima_pmu_get_ip_mask(struct lima_ip *ip)
  33{
  34        struct lima_device *dev = ip->dev;
  35        u32 ret = 0;
  36        int i;
  37
  38        ret |= LIMA_PMU_POWER_GP0_MASK;
  39
  40        if (dev->id == lima_gpu_mali400) {
  41                ret |= LIMA_PMU_POWER_L2_MASK;
  42                for (i = 0; i < 4; i++) {
  43                        if (dev->ip[lima_ip_pp0 + i].present)
  44                                ret |= LIMA_PMU_POWER_PP_MASK(i);
  45                }
  46        } else {
  47                if (dev->ip[lima_ip_pp0].present)
  48                        ret |= LIMA450_PMU_POWER_PP0_MASK;
  49                for (i = lima_ip_pp1; i <= lima_ip_pp3; i++) {
  50                        if (dev->ip[i].present) {
  51                                ret |= LIMA450_PMU_POWER_PP13_MASK;
  52                                break;
  53                        }
  54                }
  55                for (i = lima_ip_pp4; i <= lima_ip_pp7; i++) {
  56                        if (dev->ip[i].present) {
  57                                ret |= LIMA450_PMU_POWER_PP47_MASK;
  58                                break;
  59                        }
  60                }
  61        }
  62
  63        return ret;
  64}
  65
  66static int lima_pmu_hw_init(struct lima_ip *ip)
  67{
  68        int err;
  69        u32 stat;
  70
  71        pmu_write(LIMA_PMU_INT_MASK, 0);
  72
  73        /* If this value is too low, when in high GPU clk freq,
  74         * GPU will be in unstable state.
  75         */
  76        pmu_write(LIMA_PMU_SW_DELAY, 0xffff);
  77
  78        /* status reg 1=off 0=on */
  79        stat = pmu_read(LIMA_PMU_STATUS);
  80
  81        /* power up all ip */
  82        if (stat) {
  83                pmu_write(LIMA_PMU_POWER_UP, stat);
  84                err = lima_pmu_wait_cmd(ip);
  85                if (err)
  86                        return err;
  87        }
  88        return 0;
  89}
  90
  91static void lima_pmu_hw_fini(struct lima_ip *ip)
  92{
  93        u32 stat;
  94
  95        if (!ip->data.mask)
  96                ip->data.mask = lima_pmu_get_ip_mask(ip);
  97
  98        stat = ~pmu_read(LIMA_PMU_STATUS) & ip->data.mask;
  99        if (stat) {
 100                pmu_write(LIMA_PMU_POWER_DOWN, stat);
 101
 102                /* Don't wait for interrupt on Mali400 if all domains are
 103                 * powered off because the HW won't generate an interrupt
 104                 * in this case.
 105                 */
 106                if (ip->dev->id == lima_gpu_mali400)
 107                        pmu_write(LIMA_PMU_INT_CLEAR, LIMA_PMU_INT_CMD_MASK);
 108                else
 109                        lima_pmu_wait_cmd(ip);
 110        }
 111}
 112
 113int lima_pmu_resume(struct lima_ip *ip)
 114{
 115        return lima_pmu_hw_init(ip);
 116}
 117
 118void lima_pmu_suspend(struct lima_ip *ip)
 119{
 120        lima_pmu_hw_fini(ip);
 121}
 122
 123int lima_pmu_init(struct lima_ip *ip)
 124{
 125        return lima_pmu_hw_init(ip);
 126}
 127
 128void lima_pmu_fini(struct lima_ip *ip)
 129{
 130        lima_pmu_hw_fini(ip);
 131}
 132