blob: 43498279afef75f43e2a1700311f087f8cb51770 [file] [log] [blame]
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* GXP mailbox driver.
*
* Copyright (C) 2020-2022 Google LLC
*/
#ifndef __GXP_MAILBOX_DRIVER_H__
#define __GXP_MAILBOX_DRIVER_H__
#include "gxp-config.h"
#include "gxp-mailbox.h"
#if !GXP_USE_LEGACY_MAILBOX
#include <gcip/gcip-mailbox.h>
#endif
/* Utilities of circular queue operations */
#define CIRCULAR_QUEUE_INDEX_MASK(wrap_bit) (wrap_bit - 1)
#define CIRCULAR_QUEUE_WRAPPED(idx, wrap_bit) ((idx)&wrap_bit)
#define CIRCULAR_QUEUE_REAL_INDEX(idx, wrap_bit) \
((idx)&CIRCULAR_QUEUE_INDEX_MASK(wrap_bit))
/*
* Returns the number of elements in a circular queue given its @head, @tail,
* and @queue_size.
*/
u32 gxp_circ_queue_cnt(u32 head, u32 tail, u32 queue_size, u32 wrap_bit);
/* Increases @index of a circular queue by @inc. */
u32 gxp_circ_queue_inc(u32 index, u32 inc, u32 queue_size, u32 wrap_bit);
void gxp_mailbox_driver_init(struct gxp_mailbox *mailbox);
void gxp_mailbox_driver_exit(struct gxp_mailbox *mailbox);
void gxp_mailbox_driver_enable_interrupts(struct gxp_mailbox *mailbox);
void gxp_mailbox_driver_disable_interrupts(struct gxp_mailbox *mailbox);
void __iomem *gxp_mailbox_get_csr_base(struct gxp_dev *gxp, uint index);
void __iomem *gxp_mailbox_get_data_base(struct gxp_dev *gxp, uint index);
void gxp_mailbox_reset_hw(struct gxp_mailbox *mailbox);
/**
* gxp_mailbox_generate_device_interrupt(): Trigger interrupt to device.
* @mailbox: Mailbox for which to generate interrupt.
* @int_mask: Bitset of interrupt line to trigger.
*/
void gxp_mailbox_generate_device_interrupt(struct gxp_mailbox *mailbox,
u32 int_mask);
/**
* gxp_mailbox_clear_interrupts() - Clear set bits corresponding to interrupts
* coming to AP/Host.
* @mailbox: Mailbox for which to clear interrupts.
* @intr_bits: Bitset of interrupt lines to clear.
*/
void gxp_mailbox_clear_interrupts(struct gxp_mailbox *mailbox, u32 intr_bits);
/**
* gxp_mailbox_enable_interrupt() - Enable the interrupt coming to AP/Host.
* @mailbox: Mailbox for which to enable interrupts.
*/
void gxp_mailbox_enable_interrupt(struct gxp_mailbox *mailbox);
/**
* gxp_mailbox_get_interrupt_status() - Retrieve the set interrupt bits coming
* to AP/Host.
* @mailbox: Mailbox for which to get interrupt status.
*/
u32 gxp_mailbox_get_interrupt_status(struct gxp_mailbox *mailbox);
/* gxp_mailbox_wait_for_device_mailbox_init() - Wait for mailbox to get
* enabled/initialised by device.
* @mailbox: Mailbox to get it enabled from device end.
*
* Return: 0 on success else -ETIMEDOUT.
*/
int gxp_mailbox_wait_for_device_mailbox_init(struct gxp_mailbox *mailbox);
/**
* gxp_mailbox_chip_irq_handler() - IRQ handler based on chip.
* @mailbox: Mailbox on which interrupt received.
*
* Context: Interrupt context.
*/
void gxp_mailbox_chip_irq_handler(struct gxp_mailbox *mailbox);
void gxp_mailbox_write_status(struct gxp_mailbox *mailbox, u32 status);
void gxp_mailbox_write_descriptor(struct gxp_mailbox *mailbox,
dma_addr_t descriptor_addr);
void gxp_mailbox_write_cmd_queue_tail(struct gxp_mailbox *mailbox, u16 val);
void gxp_mailbox_write_resp_queue_head(struct gxp_mailbox *mailbox, u16 val);
u16 gxp_mailbox_read_cmd_queue_head(struct gxp_mailbox *mailbox);
u16 gxp_mailbox_read_resp_queue_tail(struct gxp_mailbox *mailbox);
/*
* These functions are only used to initialize these values on mailbox startup.
* During normal use, the host must not write the command queue head or response
* queue tail, as the device sets those values.
*/
void gxp_mailbox_write_cmd_queue_head(struct gxp_mailbox *mailbox, u16 val);
void gxp_mailbox_write_resp_queue_tail(struct gxp_mailbox *mailbox, u16 val);
u16 gxp_mailbox_read_cmd_queue_tail(struct gxp_mailbox *mailbox);
u16 gxp_mailbox_read_resp_queue_head(struct gxp_mailbox *mailbox);
/* Sets mailbox->cmd_queue_tail and corresponding CSR on device. */
void gxp_mailbox_set_cmd_queue_tail(struct gxp_mailbox *mailbox, u32 value);
/* Sets mailbox->resp_queue_head and corresponding CSR on device. */
void gxp_mailbox_set_resp_queue_head(struct gxp_mailbox *mailbox, u32 value);
void gxp_mailbox_set_control(struct gxp_mailbox *mailbox, u32 val);
/*
* Increases the command queue tail by @inc.
*
* The queue uses the mirrored circular buffer arrangement. Each index (head and
* tail) has a wrap bit, represented by the constant CIRCULAR_QUEUE_WRAP_BIT.
* Whenever an index is increased and will exceed the end of the queue, the wrap
* bit is xor-ed.
*
* This method will update both mailbox->cmd_queue_tail and CSR on device.
*
* Returns 0 on success.
* If command queue tail will exceed command queue head after adding @inc,
* -EBUSY is returned and all fields remain unchanged. The caller should
* handle this case and implement a mechanism to wait until the consumer
* consumes commands.
*
* This doesn't acquire any locks internally. The caller may have to hold its own
* lock before calling this function. If the caller must hold `@mailbox->cmd_queue_lock`
* before calling this, please use `gxp_mailbox_inc_cmd_queue_tail_locked` function instead.
*/
int gxp_mailbox_inc_cmd_queue_tail_nolock(struct gxp_mailbox *mailbox, u32 inc,
u32 wrap_bit);
/*
* Wrapper function of `gxp_mailbox_inc_cmd_queue_tail_nolock`.
* Caller must hold @mailbox->cmd_queue_lock.
*/
int gxp_mailbox_inc_cmd_queue_tail_locked(struct gxp_mailbox *mailbox, u32 inc,
u32 wrap_bit);
/*
* Increases the response queue head by @inc.
*
* The queue uses the mirrored circular buffer arrangement. Each index (head and
* tail) has a wrap bit, represented by the constant CIRCULAR_QUEUE_WRAP_BIT.
* Whenever an index is increased and will exceed the end of the queue, the wrap
* bit is xor-ed.
*
* This method will update both mailbox->resp_queue_head and CSR on device.
*
* Returns 0 on success.
* -EINVAL is returned if the queue head will exceed tail of queue, and no
* fields or CSR is updated in this case.
*
* This doesn't acquire any locks internally. The caller may have to hold its own
* lock before calling this function. If the caller must hold `@mailbox->cmd_queue_lock`
* before calling this, please use `gxp_mailbox_inc_cmd_queue_tail_locked` function instead.
*/
int gxp_mailbox_inc_resp_queue_head_nolock(struct gxp_mailbox *mailbox, u32 inc,
u32 wrap_bit);
/*
* Wrapper function of `gxp_mailbox_inc_resp_queue_head_nolock`.
* Caller must hold @mailbox->resp_queue_lock.
*/
int gxp_mailbox_inc_resp_queue_head_locked(struct gxp_mailbox *mailbox, u32 inc,
u32 wrap_bit);
#if !GXP_USE_LEGACY_MAILBOX
/*
* Following functions are used when setting the operators of `struct gcip_mailbox_ops`.
* To use these functions, @mailbox->data should be set as an instance of `struct gxp_mailbox`.
*/
u32 gxp_mailbox_gcip_ops_get_cmd_queue_head(struct gcip_mailbox *mailbox);
u32 gxp_mailbox_gcip_ops_get_cmd_queue_tail(struct gcip_mailbox *mailbox);
void gxp_mailbox_gcip_ops_inc_cmd_queue_tail(struct gcip_mailbox *mailbox,
u32 inc);
int gxp_mailbox_gcip_ops_acquire_cmd_queue_lock(struct gcip_mailbox *mailbox,
bool try, bool *atomic);
void gxp_mailbox_gcip_ops_release_cmd_queue_lock(struct gcip_mailbox *mailbox);
u32 gxp_mailbox_gcip_ops_get_resp_queue_size(struct gcip_mailbox *mailbox);
u32 gxp_mailbox_gcip_ops_get_resp_queue_head(struct gcip_mailbox *mailbox);
u32 gxp_mailbox_gcip_ops_get_resp_queue_tail(struct gcip_mailbox *mailbox);
void gxp_mailbox_gcip_ops_inc_resp_queue_head(struct gcip_mailbox *mailbox,
u32 inc);
int gxp_mailbox_gcip_ops_acquire_resp_queue_lock(struct gcip_mailbox *mailbox,
bool try, bool *atomic);
void gxp_mailbox_gcip_ops_release_resp_queue_lock(struct gcip_mailbox *mailbox);
void gxp_mailbox_gcip_ops_acquire_wait_list_lock(struct gcip_mailbox *mailbox,
bool irqsave,
unsigned long *flags);
void gxp_mailbox_gcip_ops_release_wait_list_lock(struct gcip_mailbox *mailbox,
bool irqrestore,
unsigned long flags);
int gxp_mailbox_gcip_ops_wait_for_cmd_queue_not_full(
struct gcip_mailbox *mailbox);
int gxp_mailbox_gcip_ops_after_enqueue_cmd(struct gcip_mailbox *mailbox,
void *cmd);
void gxp_mailbox_gcip_ops_after_fetch_resps(struct gcip_mailbox *mailbox,
u32 num_resps);
bool gxp_mailbox_gcip_ops_is_block_off(struct gcip_mailbox *mailbox);
#endif /* !GXP_USE_LEGACY_MAILBOX */
#endif /* __GXP_MAILBOX_DRIVER_H__ */