| /* |
| * Copyright 2018 NXP |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but |
| * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * for more details. |
| */ |
| |
| #include <linux/io.h> |
| #include <linux/module.h> |
| #include <linux/mutex.h> |
| #include <linux/platform_device.h> |
| #include <linux/types.h> |
| #include "dpu-prv.h" |
| |
| #define PIXENGCFG_STATIC 0x8 |
| |
| struct dpu_store { |
| void __iomem *pec_base; |
| void __iomem *base; |
| struct mutex mutex; |
| int id; |
| bool inuse; |
| struct dpu_soc *dpu; |
| }; |
| |
| static inline u32 dpu_pec_st_read(struct dpu_store *st, unsigned int offset) |
| { |
| return readl(st->pec_base + offset); |
| } |
| |
| static inline void dpu_pec_st_write(struct dpu_store *st, u32 value, |
| unsigned int offset) |
| { |
| writel(value, st->pec_base + offset); |
| } |
| |
| void store_pixengcfg_syncmode_fixup(struct dpu_store *st, bool enable) |
| { |
| struct dpu_soc *dpu; |
| u32 val; |
| |
| if (!st) |
| return; |
| |
| dpu = st->dpu; |
| |
| if (!dpu->devtype->has_syncmode_fixup) |
| return; |
| |
| mutex_lock(&st->mutex); |
| val = dpu_pec_st_read(st, PIXENGCFG_STATIC); |
| if (enable) |
| val |= BIT(16); |
| else |
| val &= ~BIT(16); |
| dpu_pec_st_write(st, val, PIXENGCFG_STATIC); |
| mutex_unlock(&st->mutex); |
| } |
| EXPORT_SYMBOL_GPL(store_pixengcfg_syncmode_fixup); |
| |
| struct dpu_store *dpu_st_get(struct dpu_soc *dpu, int id) |
| { |
| struct dpu_store *st; |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(st_ids); i++) |
| if (st_ids[i] == id) |
| break; |
| |
| if (i == ARRAY_SIZE(st_ids)) |
| return ERR_PTR(-EINVAL); |
| |
| st = dpu->st_priv[i]; |
| |
| mutex_lock(&st->mutex); |
| |
| if (st->inuse) { |
| mutex_unlock(&st->mutex); |
| return ERR_PTR(-EBUSY); |
| } |
| |
| st->inuse = true; |
| |
| mutex_unlock(&st->mutex); |
| |
| return st; |
| } |
| EXPORT_SYMBOL_GPL(dpu_st_get); |
| |
| void dpu_st_put(struct dpu_store *st) |
| { |
| mutex_lock(&st->mutex); |
| |
| st->inuse = false; |
| |
| mutex_unlock(&st->mutex); |
| } |
| EXPORT_SYMBOL_GPL(dpu_st_put); |
| |
| int dpu_st_init(struct dpu_soc *dpu, unsigned int id, |
| unsigned long pec_base, unsigned long base) |
| { |
| struct dpu_store *st; |
| int i; |
| |
| st = devm_kzalloc(dpu->dev, sizeof(*st), GFP_KERNEL); |
| if (!st) |
| return -ENOMEM; |
| |
| for (i = 0; i < ARRAY_SIZE(st_ids); i++) |
| if (st_ids[i] == id) |
| break; |
| |
| if (i == ARRAY_SIZE(st_ids)) |
| return -EINVAL; |
| |
| dpu->st_priv[i] = st; |
| |
| st->pec_base = devm_ioremap(dpu->dev, pec_base, SZ_32); |
| if (!st->pec_base) |
| return -ENOMEM; |
| |
| st->base = devm_ioremap(dpu->dev, base, SZ_256); |
| if (!st->base) |
| return -ENOMEM; |
| |
| st->dpu = dpu; |
| st->id = id; |
| |
| mutex_init(&st->mutex); |
| |
| return 0; |
| } |