linux/drivers/soc/mediatek/mtk-scpsys.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015 Pengutronix, Sascha Hauer <kernel@pengutronix.de>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 as
   6 * published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13#include <linux/clk.h>
  14#include <linux/delay.h>
  15#include <linux/io.h>
  16#include <linux/kernel.h>
  17#include <linux/mfd/syscon.h>
  18#include <linux/init.h>
  19#include <linux/of_device.h>
  20#include <linux/platform_device.h>
  21#include <linux/pm_domain.h>
  22#include <linux/regmap.h>
  23#include <linux/soc/mediatek/infracfg.h>
  24#include <linux/regulator/consumer.h>
  25#include <dt-bindings/power/mt8173-power.h>
  26
  27#define SPM_VDE_PWR_CON                 0x0210
  28#define SPM_MFG_PWR_CON                 0x0214
  29#define SPM_VEN_PWR_CON                 0x0230
  30#define SPM_ISP_PWR_CON                 0x0238
  31#define SPM_DIS_PWR_CON                 0x023c
  32#define SPM_VEN2_PWR_CON                0x0298
  33#define SPM_AUDIO_PWR_CON               0x029c
  34#define SPM_MFG_2D_PWR_CON              0x02c0
  35#define SPM_MFG_ASYNC_PWR_CON           0x02c4
  36#define SPM_USB_PWR_CON                 0x02cc
  37#define SPM_PWR_STATUS                  0x060c
  38#define SPM_PWR_STATUS_2ND              0x0610
  39
  40#define PWR_RST_B_BIT                   BIT(0)
  41#define PWR_ISO_BIT                     BIT(1)
  42#define PWR_ON_BIT                      BIT(2)
  43#define PWR_ON_2ND_BIT                  BIT(3)
  44#define PWR_CLK_DIS_BIT                 BIT(4)
  45
  46#define PWR_STATUS_DISP                 BIT(3)
  47#define PWR_STATUS_MFG                  BIT(4)
  48#define PWR_STATUS_ISP                  BIT(5)
  49#define PWR_STATUS_VDEC                 BIT(7)
  50#define PWR_STATUS_VENC_LT              BIT(20)
  51#define PWR_STATUS_VENC                 BIT(21)
  52#define PWR_STATUS_MFG_2D               BIT(22)
  53#define PWR_STATUS_MFG_ASYNC            BIT(23)
  54#define PWR_STATUS_AUDIO                BIT(24)
  55#define PWR_STATUS_USB                  BIT(25)
  56
  57enum clk_id {
  58        MT8173_CLK_NONE,
  59        MT8173_CLK_MM,
  60        MT8173_CLK_MFG,
  61        MT8173_CLK_VENC,
  62        MT8173_CLK_VENC_LT,
  63        MT8173_CLK_MAX,
  64};
  65
  66#define MAX_CLKS        2
  67
  68struct scp_domain_data {
  69        const char *name;
  70        u32 sta_mask;
  71        int ctl_offs;
  72        u32 sram_pdn_bits;
  73        u32 sram_pdn_ack_bits;
  74        u32 bus_prot_mask;
  75        enum clk_id clk_id[MAX_CLKS];
  76        bool active_wakeup;
  77};
  78
  79static const struct scp_domain_data scp_domain_data[] = {
  80        [MT8173_POWER_DOMAIN_VDEC] = {
  81                .name = "vdec",
  82                .sta_mask = PWR_STATUS_VDEC,
  83                .ctl_offs = SPM_VDE_PWR_CON,
  84                .sram_pdn_bits = GENMASK(11, 8),
  85                .sram_pdn_ack_bits = GENMASK(12, 12),
  86                .clk_id = {MT8173_CLK_MM},
  87        },
  88        [MT8173_POWER_DOMAIN_VENC] = {
  89                .name = "venc",
  90                .sta_mask = PWR_STATUS_VENC,
  91                .ctl_offs = SPM_VEN_PWR_CON,
  92                .sram_pdn_bits = GENMASK(11, 8),
  93                .sram_pdn_ack_bits = GENMASK(15, 12),
  94                .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC},
  95        },
  96        [MT8173_POWER_DOMAIN_ISP] = {
  97                .name = "isp",
  98                .sta_mask = PWR_STATUS_ISP,
  99                .ctl_offs = SPM_ISP_PWR_CON,
 100                .sram_pdn_bits = GENMASK(11, 8),
 101                .sram_pdn_ack_bits = GENMASK(13, 12),
 102                .clk_id = {MT8173_CLK_MM},
 103        },
 104        [MT8173_POWER_DOMAIN_MM] = {
 105                .name = "mm",
 106                .sta_mask = PWR_STATUS_DISP,
 107                .ctl_offs = SPM_DIS_PWR_CON,
 108                .sram_pdn_bits = GENMASK(11, 8),
 109                .sram_pdn_ack_bits = GENMASK(12, 12),
 110                .clk_id = {MT8173_CLK_MM},
 111                .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 |
 112                        MT8173_TOP_AXI_PROT_EN_MM_M1,
 113        },
 114        [MT8173_POWER_DOMAIN_VENC_LT] = {
 115                .name = "venc_lt",
 116                .sta_mask = PWR_STATUS_VENC_LT,
 117                .ctl_offs = SPM_VEN2_PWR_CON,
 118                .sram_pdn_bits = GENMASK(11, 8),
 119                .sram_pdn_ack_bits = GENMASK(15, 12),
 120                .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT},
 121        },
 122        [MT8173_POWER_DOMAIN_AUDIO] = {
 123                .name = "audio",
 124                .sta_mask = PWR_STATUS_AUDIO,
 125                .ctl_offs = SPM_AUDIO_PWR_CON,
 126                .sram_pdn_bits = GENMASK(11, 8),
 127                .sram_pdn_ack_bits = GENMASK(15, 12),
 128                .clk_id = {MT8173_CLK_NONE},
 129        },
 130        [MT8173_POWER_DOMAIN_USB] = {
 131                .name = "usb",
 132                .sta_mask = PWR_STATUS_USB,
 133                .ctl_offs = SPM_USB_PWR_CON,
 134                .sram_pdn_bits = GENMASK(11, 8),
 135                .sram_pdn_ack_bits = GENMASK(15, 12),
 136                .clk_id = {MT8173_CLK_NONE},
 137                .active_wakeup = true,
 138        },
 139        [MT8173_POWER_DOMAIN_MFG_ASYNC] = {
 140                .name = "mfg_async",
 141                .sta_mask = PWR_STATUS_MFG_ASYNC,
 142                .ctl_offs = SPM_MFG_ASYNC_PWR_CON,
 143                .sram_pdn_bits = GENMASK(11, 8),
 144                .sram_pdn_ack_bits = 0,
 145                .clk_id = {MT8173_CLK_MFG},
 146        },
 147        [MT8173_POWER_DOMAIN_MFG_2D] = {
 148                .name = "mfg_2d",
 149                .sta_mask = PWR_STATUS_MFG_2D,
 150                .ctl_offs = SPM_MFG_2D_PWR_CON,
 151                .sram_pdn_bits = GENMASK(11, 8),
 152                .sram_pdn_ack_bits = GENMASK(13, 12),
 153                .clk_id = {MT8173_CLK_NONE},
 154        },
 155        [MT8173_POWER_DOMAIN_MFG] = {
 156                .name = "mfg",
 157                .sta_mask = PWR_STATUS_MFG,
 158                .ctl_offs = SPM_MFG_PWR_CON,
 159                .sram_pdn_bits = GENMASK(13, 8),
 160                .sram_pdn_ack_bits = GENMASK(21, 16),
 161                .clk_id = {MT8173_CLK_NONE},
 162                .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S |
 163                        MT8173_TOP_AXI_PROT_EN_MFG_M0 |
 164                        MT8173_TOP_AXI_PROT_EN_MFG_M1 |
 165                        MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT,
 166        },
 167};
 168
 169#define NUM_DOMAINS     ARRAY_SIZE(scp_domain_data)
 170
 171struct scp;
 172
 173struct scp_domain {
 174        struct generic_pm_domain genpd;
 175        struct scp *scp;
 176        struct clk *clk[MAX_CLKS];
 177        const struct scp_domain_data *data;
 178        struct regulator *supply;
 179};
 180
 181struct scp {
 182        struct scp_domain domains[NUM_DOMAINS];
 183        struct genpd_onecell_data pd_data;
 184        struct device *dev;
 185        void __iomem *base;
 186        struct regmap *infracfg;
 187};
 188
 189static int scpsys_domain_is_on(struct scp_domain *scpd)
 190{
 191        struct scp *scp = scpd->scp;
 192
 193        u32 status = readl(scp->base + SPM_PWR_STATUS) & scpd->data->sta_mask;
 194        u32 status2 = readl(scp->base + SPM_PWR_STATUS_2ND) &
 195                                scpd->data->sta_mask;
 196
 197        /*
 198         * A domain is on when both status bits are set. If only one is set
 199         * return an error. This happens while powering up a domain
 200         */
 201
 202        if (status && status2)
 203                return true;
 204        if (!status && !status2)
 205                return false;
 206
 207        return -EINVAL;
 208}
 209
 210static int scpsys_power_on(struct generic_pm_domain *genpd)
 211{
 212        struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
 213        struct scp *scp = scpd->scp;
 214        unsigned long timeout;
 215        bool expired;
 216        void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
 217        u32 sram_pdn_ack = scpd->data->sram_pdn_ack_bits;
 218        u32 val;
 219        int ret;
 220        int i;
 221
 222        if (scpd->supply) {
 223                ret = regulator_enable(scpd->supply);
 224                if (ret)
 225                        return ret;
 226        }
 227
 228        for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++) {
 229                ret = clk_prepare_enable(scpd->clk[i]);
 230                if (ret) {
 231                        for (--i; i >= 0; i--)
 232                                clk_disable_unprepare(scpd->clk[i]);
 233
 234                        goto err_clk;
 235                }
 236        }
 237
 238        val = readl(ctl_addr);
 239        val |= PWR_ON_BIT;
 240        writel(val, ctl_addr);
 241        val |= PWR_ON_2ND_BIT;
 242        writel(val, ctl_addr);
 243
 244        /* wait until PWR_ACK = 1 */
 245        timeout = jiffies + HZ;
 246        expired = false;
 247        while (1) {
 248                ret = scpsys_domain_is_on(scpd);
 249                if (ret > 0)
 250                        break;
 251
 252                if (expired) {
 253                        ret = -ETIMEDOUT;
 254                        goto err_pwr_ack;
 255                }
 256
 257                cpu_relax();
 258
 259                if (time_after(jiffies, timeout))
 260                        expired = true;
 261        }
 262
 263        val &= ~PWR_CLK_DIS_BIT;
 264        writel(val, ctl_addr);
 265
 266        val &= ~PWR_ISO_BIT;
 267        writel(val, ctl_addr);
 268
 269        val |= PWR_RST_B_BIT;
 270        writel(val, ctl_addr);
 271
 272        val &= ~scpd->data->sram_pdn_bits;
 273        writel(val, ctl_addr);
 274
 275        /* wait until SRAM_PDN_ACK all 0 */
 276        timeout = jiffies + HZ;
 277        expired = false;
 278        while (sram_pdn_ack && (readl(ctl_addr) & sram_pdn_ack)) {
 279
 280                if (expired) {
 281                        ret = -ETIMEDOUT;
 282                        goto err_pwr_ack;
 283                }
 284
 285                cpu_relax();
 286
 287                if (time_after(jiffies, timeout))
 288                        expired = true;
 289        }
 290
 291        if (scpd->data->bus_prot_mask) {
 292                ret = mtk_infracfg_clear_bus_protection(scp->infracfg,
 293                                scpd->data->bus_prot_mask);
 294                if (ret)
 295                        goto err_pwr_ack;
 296        }
 297
 298        return 0;
 299
 300err_pwr_ack:
 301        for (i = MAX_CLKS - 1; i >= 0; i--) {
 302                if (scpd->clk[i])
 303                        clk_disable_unprepare(scpd->clk[i]);
 304        }
 305err_clk:
 306        if (scpd->supply)
 307                regulator_disable(scpd->supply);
 308
 309        dev_err(scp->dev, "Failed to power on domain %s\n", genpd->name);
 310
 311        return ret;
 312}
 313
 314static int scpsys_power_off(struct generic_pm_domain *genpd)
 315{
 316        struct scp_domain *scpd = container_of(genpd, struct scp_domain, genpd);
 317        struct scp *scp = scpd->scp;
 318        unsigned long timeout;
 319        bool expired;
 320        void __iomem *ctl_addr = scp->base + scpd->data->ctl_offs;
 321        u32 pdn_ack = scpd->data->sram_pdn_ack_bits;
 322        u32 val;
 323        int ret;
 324        int i;
 325
 326        if (scpd->data->bus_prot_mask) {
 327                ret = mtk_infracfg_set_bus_protection(scp->infracfg,
 328                                scpd->data->bus_prot_mask);
 329                if (ret)
 330                        goto out;
 331        }
 332
 333        val = readl(ctl_addr);
 334        val |= scpd->data->sram_pdn_bits;
 335        writel(val, ctl_addr);
 336
 337        /* wait until SRAM_PDN_ACK all 1 */
 338        timeout = jiffies + HZ;
 339        expired = false;
 340        while (pdn_ack && (readl(ctl_addr) & pdn_ack) != pdn_ack) {
 341                if (expired) {
 342                        ret = -ETIMEDOUT;
 343                        goto out;
 344                }
 345
 346                cpu_relax();
 347
 348                if (time_after(jiffies, timeout))
 349                        expired = true;
 350        }
 351
 352        val |= PWR_ISO_BIT;
 353        writel(val, ctl_addr);
 354
 355        val &= ~PWR_RST_B_BIT;
 356        writel(val, ctl_addr);
 357
 358        val |= PWR_CLK_DIS_BIT;
 359        writel(val, ctl_addr);
 360
 361        val &= ~PWR_ON_BIT;
 362        writel(val, ctl_addr);
 363
 364        val &= ~PWR_ON_2ND_BIT;
 365        writel(val, ctl_addr);
 366
 367        /* wait until PWR_ACK = 0 */
 368        timeout = jiffies + HZ;
 369        expired = false;
 370        while (1) {
 371                ret = scpsys_domain_is_on(scpd);
 372                if (ret == 0)
 373                        break;
 374
 375                if (expired) {
 376                        ret = -ETIMEDOUT;
 377                        goto out;
 378                }
 379
 380                cpu_relax();
 381
 382                if (time_after(jiffies, timeout))
 383                        expired = true;
 384        }
 385
 386        for (i = 0; i < MAX_CLKS && scpd->clk[i]; i++)
 387                clk_disable_unprepare(scpd->clk[i]);
 388
 389        if (scpd->supply)
 390                regulator_disable(scpd->supply);
 391
 392        return 0;
 393
 394out:
 395        dev_err(scp->dev, "Failed to power off domain %s\n", genpd->name);
 396
 397        return ret;
 398}
 399
 400static bool scpsys_active_wakeup(struct device *dev)
 401{
 402        struct generic_pm_domain *genpd;
 403        struct scp_domain *scpd;
 404
 405        genpd = pd_to_genpd(dev->pm_domain);
 406        scpd = container_of(genpd, struct scp_domain, genpd);
 407
 408        return scpd->data->active_wakeup;
 409}
 410
 411static int scpsys_probe(struct platform_device *pdev)
 412{
 413        struct genpd_onecell_data *pd_data;
 414        struct resource *res;
 415        int i, j, ret;
 416        struct scp *scp;
 417        struct clk *clk[MT8173_CLK_MAX];
 418
 419        scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL);
 420        if (!scp)
 421                return -ENOMEM;
 422
 423        scp->dev = &pdev->dev;
 424
 425        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 426        scp->base = devm_ioremap_resource(&pdev->dev, res);
 427        if (IS_ERR(scp->base))
 428                return PTR_ERR(scp->base);
 429
 430        pd_data = &scp->pd_data;
 431
 432        pd_data->domains = devm_kzalloc(&pdev->dev,
 433                        sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL);
 434        if (!pd_data->domains)
 435                return -ENOMEM;
 436
 437        clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm");
 438        if (IS_ERR(clk[MT8173_CLK_MM]))
 439                return PTR_ERR(clk[MT8173_CLK_MM]);
 440
 441        clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg");
 442        if (IS_ERR(clk[MT8173_CLK_MFG]))
 443                return PTR_ERR(clk[MT8173_CLK_MFG]);
 444
 445        clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc");
 446        if (IS_ERR(clk[MT8173_CLK_VENC]))
 447                return PTR_ERR(clk[MT8173_CLK_VENC]);
 448
 449        clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt");
 450        if (IS_ERR(clk[MT8173_CLK_VENC_LT]))
 451                return PTR_ERR(clk[MT8173_CLK_VENC_LT]);
 452
 453        scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
 454                        "infracfg");
 455        if (IS_ERR(scp->infracfg)) {
 456                dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n",
 457                                PTR_ERR(scp->infracfg));
 458                return PTR_ERR(scp->infracfg);
 459        }
 460
 461        for (i = 0; i < NUM_DOMAINS; i++) {
 462                struct scp_domain *scpd = &scp->domains[i];
 463                const struct scp_domain_data *data = &scp_domain_data[i];
 464
 465                scpd->supply = devm_regulator_get_optional(&pdev->dev, data->name);
 466                if (IS_ERR(scpd->supply)) {
 467                        if (PTR_ERR(scpd->supply) == -ENODEV)
 468                                scpd->supply = NULL;
 469                        else
 470                                return PTR_ERR(scpd->supply);
 471                }
 472        }
 473
 474        pd_data->num_domains = NUM_DOMAINS;
 475
 476        for (i = 0; i < NUM_DOMAINS; i++) {
 477                struct scp_domain *scpd = &scp->domains[i];
 478                struct generic_pm_domain *genpd = &scpd->genpd;
 479                const struct scp_domain_data *data = &scp_domain_data[i];
 480
 481                pd_data->domains[i] = genpd;
 482                scpd->scp = scp;
 483
 484                scpd->data = data;
 485                for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++)
 486                        scpd->clk[j] = clk[data->clk_id[j]];
 487
 488                genpd->name = data->name;
 489                genpd->power_off = scpsys_power_off;
 490                genpd->power_on = scpsys_power_on;
 491                genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
 492
 493                /*
 494                 * Initially turn on all domains to make the domains usable
 495                 * with !CONFIG_PM and to get the hardware in sync with the
 496                 * software.  The unused domains will be switched off during
 497                 * late_init time.
 498                 */
 499                genpd->power_on(genpd);
 500
 501                pm_genpd_init(genpd, NULL, false);
 502        }
 503
 504        /*
 505         * We are not allowed to fail here since there is no way to unregister
 506         * a power domain. Once registered above we have to keep the domains
 507         * valid.
 508         */
 509
 510        ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC],
 511                pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]);
 512        if (ret && IS_ENABLED(CONFIG_PM))
 513                dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
 514
 515        ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D],
 516                pd_data->domains[MT8173_POWER_DOMAIN_MFG]);
 517        if (ret && IS_ENABLED(CONFIG_PM))
 518                dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret);
 519
 520        ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data);
 521        if (ret)
 522                dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret);
 523
 524        return 0;
 525}
 526
 527static const struct of_device_id of_scpsys_match_tbl[] = {
 528        {
 529                .compatible = "mediatek,mt8173-scpsys",
 530        }, {
 531                /* sentinel */
 532        }
 533};
 534
 535static struct platform_driver scpsys_drv = {
 536        .probe = scpsys_probe,
 537        .driver = {
 538                .name = "mtk-scpsys",
 539                .suppress_bind_attrs = true,
 540                .owner = THIS_MODULE,
 541                .of_match_table = of_match_ptr(of_scpsys_match_tbl),
 542        },
 543};
 544builtin_platform_driver(scpsys_drv);
 545